Php 遍历 Xml 个节点

Php loop throught Xml nodes

我有Xml个文件

<response>
<tag1>
    <item>
        <id>106</id>
        <title>DG</title>
    </item>
    <item>
        <id>105</id>
        <title>AC</title>
    </item>
</tag1>
<tag2>
    <item>
        <id>1</id>
        <title>DjG</title>
    </item>
    <item>
        <id>15</id>
        <title>AoC</title>
    </item>
</tag2>
</response>

我正在尝试使用此代码提取 ID 和标题

$dom = new DomDocument();
    $dom->load('xml.xml');
    $xpath = new DOMXPath($dom);

    foreach($xpath->evaluate('//response/*') as $node){
    $params =$xpath->evaluate('//response/' .$node->nodeName . '/item/*');
        foreach($params as $child) {
            echo $node->nodeName ." = " .$child->nodeName ." = " .$child->nodeValue ."\n<br>";
        }
    }

但我得到这样的结果

<br>tag1 = id = 106
<br>tag1 = title = DG
<br>tag1 = id = 105
<br>tag1 = title = AC
<br>tag2 = id = 1
<br>tag2 = title = DjG
<br>tag2 = id = 15
<br>tag2 = title = AoC

但我需要这样


tag1 = 106 = DG
tag1 = 105 = AC
tag2 = 1 = DjG
tag2 = 15 = AoC

使用此代码:

$dom = new DomDocument();
$dom->load('xml.xml');
$xpath = new DOMXPath($dom);
foreach($xpath->evaluate('//response/*') as $node){
    $params =$xpath->evaluate('//response/' .$node->nodeName . '/*');

     foreach($params as $child) 
    {
       echo $node->nodeName ." = " .$child->getElementsByTagName('id')->item(0)->textContent ." = " .$child->getElementsByTagName('title')->item(0)->textContent  ."\n<br>";
    }
}

在第二个 foreach 上,只定位 $node->nodeName,然后在内部 foreach 目标上,每个 id 一个标题。

foreach($xpath->evaluate('//response/*') as $node) {
    $tag = $node->nodeName;
    $params = $xpath->evaluate("//$tag/*");
    foreach($params as $child) {
        $id = $xpath->evaluate('string(./id)', $child);
        $title = $xpath->evaluate('string(./title)', $child);
        echo $tag ." = " .$id ." = " .$title ."\n<br>";
    }
}

Sample Output

SimpleXML 版本:

$xml = simplexml_load_file('xml.xml');
foreach($xml as $tag =>$node) {
    foreach($node as $item => $child) {
        echo $tag ." = " .$child->id ." = " .$child->title ."\n<br>";
    }
}

Sample Output

DOMXpath::evaluate() 的第二个参数是上下文节点。如果不以斜线开始 XPath 表达式,它将相对于它。因此在循环内,您通常希望使用当前节点作为表达式的上下文。

foreach ($xpath->evaluate('/absolute-expression') as $node) {
  var_dump(
     $xpath->evaluate('relative-expression', $node)
  );
}

XPath(不像 CSS 选择器)可以沿着不同的轴获取元素的属性。您可以通过以下方式获取父节点的本地名称(不带命名空间前缀):

local-name(parent::*)

使用它,您可以通过迭代 item 个元素的单个循环来解决问题。

示例:

$dom = new DomDocument();
$dom->loadXml($xml);
$xpath = new DOMXPath($dom);

foreach ($xpath->evaluate('//response/*/item') as $node) {
  echo 
    $xpath->evaluate('local-name(parent::*)', $node), ' = ',
    $xpath->evaluate('string(id)', $node), ' = ',
    $xpath->evaluate('string(title)', $node), "\n";
}

输出:

tag1 = 106 = DG
tag1 = 105 = AC
tag2 = 1 = DjG
tag2 = 15 = AoC

仅当需要为每个一级节点(tag1,tag2)调用source时。你将需要两个循环。比如输出tag*元素节点分组的items。

$dom = new DomDocument();
$dom->loadXml($xml);
$xpath = new DOMXPath($dom);

foreach ($xpath->evaluate('//response/*') as $node) {
  echo  
    $xpath->evaluate('local-name()', $node), 
    "\n--------\n";
  foreach ($xpath->evaluate('item', $node) as $item) {
    echo 
      $xpath->evaluate('string(id)', $item), ' = ',
      $xpath->evaluate('string(title)', $item), "\n";
  }
  echo "\n";
}

输出:

tag1
--------
106 = DG
105 = AC

tag2
--------
1 = DjG
15 = AoC