Вот бит 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"; }