如何遍历具有动态子级的XML元素节点


How to iterate through an XML element node with dynamic children

我目前有以下XML结构:

<root>
  <maininfo>
    <node>
      <tournament_id>3100423</tournament_id>
      <games>
        <a_0>
          <id>23523636</id>
          <type>
            <choice_4>
              <choice_id>345</choice_id>
            <choice_4>
            <choice_9>
              <choice_id>345</choice_id>
            <choice_9>
            ... etc
          </type>
        </a_0>
        <a_1></a_1>
        <a_2></a_2>
        ...etc
      </games>
    </info>
  </node>
</root>

我可以很容易地获得第一个节点元素"a_0"的id,只需执行以下操作:

maininfo[0]->a_3130432[0]->games[0]->a_1[0]->id;

我的问题是:如何自动迭代(使用foreach)所有a_0a_1a_2,并获得这些节点元素中的每个元素及其所有子元素的值,如<choice_id>345</choice_id>中的"345"?

a_0a_1+choice_4choice_9的子元素的结束数字是动态创建的,并且在_[数字]中没有逻辑为每个下一个元素加+1。

正如前面在Stackoverflow(例如在Read XML dynamic PHP中)和PHP手册(例如在Basic SimpleXML用法)中所概述的那样,您可以使用foreach迭代所有子元素。

例如,检查所有a_*元素,它只是

foreach ($xml->maininfo->node->games[0] as $name => $a) {
    echo $name, "'n";
}

输出:

a_0
a_1
a_2

然后,您需要再次对这些->type子级进行迭代。在纯PHP中,通过将一个foreach放入另一个:,可以实现

foreach ($xml->maininfo->node->games[0] as $name => $a) {
    echo $name, "'n";
    if (!$a->type[0]) {
        continue;
    }
    foreach ($a->type[0] as $name => $choice) {
        echo ' +- ', $name, "'n";
    }
}

现在输出:

a_0
 +- choice_4
 +- choice_9
a_1
a_2

这开始变得有点复杂。正如您所能想象的,由于XML以其树结构而闻名,您并不是第一个遇到这个问题的人。因此,人们发明了一种从XML文档中获取元素的查询语言:Xpath

使用Xpath,您可以像访问文件系统一样访问XML数据。正如我所知道的,每个a_*元素都是games的子元素,而每个choice_*元素都是类型的子元素

 /*/maininfo/node/games/*/type/*
  ^                     ^      ^
  |                     |   choice_*
root                    |
                       a_*

在PHP Simplexml中,这看起来像:

$choices = $xml->xpath('/*/maininfo/node/games/*/type/*');
foreach ($choices as $choice) {
    echo $choice->getName(), ': ', $choice->choice_id, "'n";
}

输出:

choice_4: 345
choice_9: 345

如本例所示,现在使用单个foreach检索数据。

如果您也需要访问<a_*>元素,则需要拥有多个foreach自己的迭代,但这甚至是一个更高级的主题,我认为这将超出您的问题的范围。

我希望到目前为止这是有帮助的。同样参见SimpleXMLElement::children(),它也提供了所有子项(如第一个示例中的->games[0])。所有示例代码都可以作为一个有效的交互式在线演示使用。

如果我理解得很好,你可以做一些事情,比如:

for($i = 0; $i < $max; ++$i){
    $a = $parentNode->{'a_'.$i};
}

使用SimpleXML:可以非常容易地完成此操作

<?php
$xmlStr = "<?xml version='1.0' standalone='yes'?>
<root>
  <maininfo>
    <node>
      <tournament_id>3100423</tournament_id>
      <games>
    <a_0>
      <id>23523636</id>
      <type>
        <choice_4>
          <choice_id>345</choice_id>
        </choice_4>
        <choice_9>
          <choice_id>345</choice_id>
        </choice_9>
      </type>
    </a_0>
    <a_1></a_1>
    <a_2></a_2>
      </games>
  </node>
  </maininfo>
</root>";
$xmlRoot = new SimpleXMLElement($xmlStr);
$i = 0;
foreach($xmlRoot->maininfo[0]->node[0]->games[0] as $a_x)
{
    echo $i++ . " - " . htmlentities($a_x->asXML()) . "<br/>";
}
?>

我修改了XML字符串的某些部分,使其语法正确。您可以在查看结果http://phpfiddle.org/main/code/56q-san