如何使用动态子级迭代XML元素节点

时间:2013-07-21 18:38:43

标签: php xml foreach simplexml

我目前有以下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;

我的问题是: 如何通过所有a_0a_1a_2自动迭代(使用foreach)并获取每个节点元素及其所有子节点的值,如{345} { {1}}?

<choice_id>345</choice_id>a_0 + a_1choice_4的子项的结束编号是动态创建的,_ [number]中的逻辑没有计数每个下一个元素都有+1。

3 个答案:

答案 0 :(得分:2)

正如之前在Stackoverflow上所述(例如在Read XML dynamic PHP中)以及一般在PHP手册中(例如在Basic SimpleXML usage中),您可以使用{迭代所有子元素{1}}。

例如,要查看所有foreach个元素,它只是

a_*

输出:

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

然后,您想再次迭代这些a_0 a_1 a_2 个孩子。通过将一个->type放入另一个{<1}},可以在纯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";
    }
}

这开始变得有点复杂。你可以想象,因为XML以它的树结构而闻名,你不是第一个遇到这个问题的人。因此,发明了一种从XML文档中获取元素的查询语言: Xpath

使用 Xpath ,您可以像访问文件系统一样访问XML数据。据我所知,每个a_0 +- choice_4 +- choice_9 a_1 a_2 元素都是a_*的子元素,而每个games元素都是类型的子元素,所以它非常直接:

choice_*

在PHP Simplexml中,它看起来像:

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

输出:

$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_*>您自己的迭代,但是甚至是一个更高级的话题,我会说这会延伸到你的问题的极限。

我希望到目前为止这有用。另请参阅SimpleXMLElement::children(),其中也包含所有子项(如第一个示例中的foreach)。所有示例代码都与a working, interactive online-demo一样可用。

答案 1 :(得分:0)

如果我理解得很清楚,你可以这样做:

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

答案 2 :(得分:0)

您可以使用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

查看结果