Get xpath from xml node in recursive function

Suppose I have some code to iterate an XML file again, like this:

$xmlfile = new SimpleXMLElement('http://www.domain.com/file.xml',null,true);
xmlRecurse($xmlfile,0);
function xmlRecurse($xmlObj,$depth) {
  foreach($xmlObj->children() as $child) {
    echo str_repeat('-',$depth).">".$child->getName().": ".$subchild."\n";
    foreach($child->attributes() as $k=>$v){
        echo "Attrib".str_repeat('-',$depth).">".$k." = ".$v."\n";
    }
    xmlRecurse($child,$depth+1);
  }
}

How would I calculate the xpath for each node so that I can save it for comparison with other code?

+3
source share
5 answers

The obvious way to do this is to pass XPath as the third parameter and build it when you dig deeper. You must consider single-user names, so you need to keep track of the number of predecessor relatives with the same name as the current child when repeating.

Working example:

function xmlRecurse($xmlObj,$depth=0,$xpath=null) {
  if (!isset($xpath)) {
    $xpath='/'.$xmlObj->getName().'/';
  }
  $position = array();

  foreach($xmlObj->children() as $child) {

    $name = $child->getName();
    if(isset($position[$name])) {
      ++$position[$name];
    }
    else {
      $position[$name]=1;
    }
    $path=$xpath.$name.'['.$position[$name].']';

    echo str_repeat('-',$depth).">".$name.": $path\n";
    foreach($child->attributes() as $k=>$v){
        echo "Attrib".str_repeat('-',$depth).">".$k." = ".$v."\n";
    }

    xmlRecurse($child,$depth+1,$path.'/');
  }
}

, , XPath . , .

+5

xmlRecurse $xpath ( node xPath) xpath- :

function xmlRecurse($xmlObj,$depth,$xpath) {
  $i=0;
  foreach($xmlObj->children() as $child) {
    echo str_repeat('-',$depth).">".$child->getName().": ".$subchild."\n";
    foreach($child->attributes() as $k=>$v){
        echo "Attrib".str_repeat('-',$depth).">".$k." = ".$v."\n";
    }
    xmlRecurse($child,$depth+1,$xpath.'/'.$child->getName().'['.$i++.']');
  }
}
+3
$domNode = dom_import_simplexml($node);
$xpath = $domNode->getNodePath();

PHP 5 >= 5.2.0.

+3

SimpleXML , , : node .

DOMDocument $node->parentNode node (, node) , , node).

+2

MightyE :

function whereami($node)
{
    if ($node instanceof SimpleXMLElement)
    {
        $node = dom_import_simplexml($node);
    }
    elseif (!$node instanceof DOMNode)
    {
        die('Not a node?');
    }

    $q     = new DOMXPath($node->ownerDocument);
    $xpath = '';

    do
    {
        $position = 1 + $q->query('preceding-sibling::*[name()="' . $node->nodeName . '"]', $node)->length;
        $xpath    = '/' . $node->nodeName . '[' . $position . ']' . $xpath;
        $node     = $node->parentNode;
    }
    while (!$node instanceof DOMDocument);

    return $xpath;
}

I would not recommend it for the case at hand (matching a whole document, as opposed to a single given node), but it may be useful for future reference.

+1
source

Source: https://habr.com/ru/post/1733915/


All Articles