PHP XML – узнать путь к известному значению

Вот бит XML:

[11] => SimpleXMLElement Object ( [@attributes] => Array ( [id] => 46e8f57e67db48b29d84dda77cf0ef51 [label] => Publications ) [section] => Array ( [0] => SimpleXMLElement Object ( [@attributes] => Array ( [id] => 9a34d6b273914f18b2273e8de7c48fd6 [label] => Journal Articles [recordId] => 1a5a5710b0e0468e92f9a2ced92906e3 ) 

Я знаю значение «46e8f57e67db48b29d84dda77cf0ef51», но его местоположение зависит от файлов. Можно ли использовать XPath для поиска пути к этому значению? Если бы не то, что можно было использовать?

Последняя пробная версия не работает:

 $search = $xml->xpath("//text()=='047ec63e32fe450e943cb678339e8102'"); while(list( , $node) = each($search)) { echo '047ec63e32fe450e943cb678339e8102',$node,"\n"; } 

У объектов DOMNode для PHP есть функция для этого: DOMNode::getNodePath()

 $xml = <<<'XML' <root> <child key="1"> <child key="2"/> <child key="3"/> </child> </root> XML; $dom = new DOMDocument(); $dom->loadXml($xml); $xpath = new DOMXpath($dom); $nodes = $xpath->evaluate('//child'); foreach ($nodes as $node) { var_dump($node->getNodePath()); } 

Вывод:

 string(11) "/root/child" string(20) "/root/child/child[1]" string(20) "/root/child/child[2]" 

SimpleXML – это оболочка для DOM, и вот функция, которая позволяет вам получить DOMNode для SimpleXMLElement: dom_import_simplexml .

 $xml = <<<'XML' <root> <child key="1"> <child key="2"/> <child key="3"/> </child> </root> XML; $structure = simplexml_load_string($xml); $elements = $structure->xpath('//child'); foreach ($elements as $element) { $node = dom_import_simplexml($element); var_dump($node->getNodePath()); } 

Для извлечения элемента по его атрибуту может использоваться xpath.

Выберите все узлы, используя джокер элемента в любом месте документа:

//*

Отфильтруйте их по атрибуту id:

//*[@id = "46e8f57e67db48b29d84dda77cf0ef51"]

 $dom = new DOMDocument(); $dom->loadXml('<node id="46e8f57e67db48b29d84dda77cf0ef51"/>'); $xpath = new DOMXpath($dom); foreach ($xpath->evaluate('//*[@id = "46e8f57e67db48b29d84dda77cf0ef51"]') as $node) { var_dump( $node->getNodePath() ); } 

Всегда ли эта строка в @id ? Тогда действительный и различный путь всегда //*[@id='46e8f57e67db48b29d84dda77cf0ef51'] , независимо от того, где он находится.

Чтобы построить путь к данному узлу, используйте $node->getNodePath() который вернет выражение XPath для текущего узла. Также возьмите этот ответ на построение выражения XPath, используя атрибуты @id , похожие на Firebug, в учетной записи.

Для SimpleXML вам придется делать все вручную. Если вам нужно поддерживать атрибут и другие пути, вам придется добавить это, этот код поддерживает только узлы элементов.

 $results = $xml->xpath("/highways/route[66]"); foreach($results as $result) { $path = ""; while (true) { // Is there an @id attribute? Shorten the path. if ($id = $result['id']) { $path = "//".$result->getName()."[@id='".(string) $id."']".$path; break; } // Determine preceding and following elements, build a position predicate from it. $preceding = $result->xpath("preceding-sibling::".$result->getName()); $following = $result->xpath("following-sibling::".$result->getName()); $predicate = (count($preceding) + count($following)) > 0 ? "[".(count($preceding)+1)."]" : ""; $path = "/".$result->getName().$predicate.$path; // Is there a parent node? Then go on. $result = $result->xpath("parent::*"); if (count($result) > 0) $result = $result[0]; else break; } echo $path."\n"; }