Получить узел-предок с PHP и xpath

Пожалуйста, простите, если следующее немного запутано, я убиваю себя, пытаясь это выработать.

Это кусок XML (экспортированный с большого сайта), который я использую для создания дерева категорий для мини-CMS. Как только у меня есть значение и имя узла, что не представляет проблемы, мне также нужно получить «родительский» каждый узел, то есть узел, предшествующий ему, который находится над ним в иерархии.

<productCategory> <genericName>DigitalCinema</genericName> <productCategories> <productCategory> <genericName>DCinemaProj</genericName> <productModels> <productModel>ProjProd-1</productModel> <productModel>ProjProd-2</productModel> <productModel>ProjProd-3</productModel> <productModel>ProjProd-4</productModel> </productModels> </productCategory> <productCategory> <genericName>DCinemaLens</genericName> </productCategory> </productCategories> </productCategory> 

Например, для DCCinemaLens productCategory-genericName мне нужно ухватить родителя как DigitalCinema и аналогично для отдельных узлов productModel , где родителем будет DCinemaProj .

Я пробовал различные разные запросы в xpath с использованием предков, предыдущего и родительского, и я все еще не вижу, чтобы захватить нужный мне узел.

Вот мой код, поскольку он стоит от отказа от моих попыток несколько минут назад.

 if ($xml->xpath('//productCategories')) { foreach($xml->xpath('//genericName | //productModel') as $genericName){ echo "<p align='center'>$genericName"; $type = $genericName->getName(); echo " - (" . $type . ") "; $derp = $xml->xpath("ancestor::productCategory[1]/genericName"); echo $derp; echo '</p>'; } } 

У меня также был некоторый успех получения информации в массиве, но он всегда возвращает все значения в XML снова.

 $key = 'genericName'; $derpgleep = $derp[$key]; echo 'Derp= ' . $derpgleep; print_r($derp); 

Надеюсь, есть очень простое решение, с которым я не обращаю внимания. Надеюсь, я поняла.

Выражение XPath, которое вы используете:

  ancestor::productCategory[1]/genericName 

будет работать, если вы сможете выполнить это выражение, начиная с текущего узла. это действительно невозможно, начиная с текущего массива $genericName поскольку оно не содержит родителей, а также предков.

Я думаю, что ваш вариант состоит в том, чтобы перепроверить все дерево XML. Это образец теста, который работает по мере необходимости на основе вашего входного образца.

 <?php $xml = simplexml_load_file("test_input1.xml"); if ($xml->xpath('//productCategories')) { foreach($xml->xpath('//genericName') as $genericName){ echo "<p align='center'>$genericName"; $type = $genericName->getName(); echo " - (" . $type . ") "; $derp = $xml->xpath("//genericName[.='" . $genericName[0] . "']/ancestor::productCategory[2]/genericName"); echo $derp[0]; echo "</p>\n"; } } ?> 

Это напечатает следующий фрагмент HTML:

 <p align='center'>DigitalCinema - (genericName) </p> <p align='center'>DCinemaProj - (genericName) DigitalCinema</p> <p align='center'>DCinemaLens - (genericName) DigitalCinema</p> 

Хотя для получения «родительского» продуктаModel вам нужен xpath вроде:

  $derp = $xml->xpath("//productModel[.='" . $productModel[0] . "']/parent::productCategory[1]/genericName"); 

Использовать (предположим, что исходный контекстный узел является либо productCategory[genericName = 'DCinemaLens'] либо productModel ):

 ../preceding-sibling::*[1] 

Проверка на основе XSLT :

 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output omit-xml-declaration="yes" indent="yes"/> <xsl:template match="/"> <xsl:copy-of select= "/*/*/productCategory [genericName = 'DCinemaLens'] /../preceding-sibling::*[1]"/> ------------- <xsl:text/> <xsl:copy-of select= "/*/*/*/*/productModel/../preceding-sibling::*[1]"/> </xsl:template> </xsl:stylesheet> 

когда это преобразование применяется к предоставленному XML-документу :

 <productCategory> <genericName>DigitalCinema</genericName> <productCategories> <productCategory> <genericName>DCinemaProj</genericName> <productModels> <productModel>ProjProd-1</productModel> <productModel>ProjProd-2</productModel> <productModel>ProjProd-3</productModel> <productModel>ProjProd-4</productModel> </productModels> </productCategory> <productCategory> <genericName>DCinemaLens</genericName> </productCategory> </productCategories> </productCategory> 

требуемые два элемента копируются на выход :

 <genericName>DigitalCinema</genericName> ------------- <genericName>DCinemaProj</genericName>