【问题标题】:How to iterate through an XML element node with dynamic children如何遍历具有动态子节点的 XML 元素节点
【发布时间】:2013-07-20 11:32:33
【问题描述】:

我目前有以下 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_0、a_1、a_2 并获取每个节点元素及其所有子元素的值,例如 &lt;choice_id&gt;345&lt;/choice_id&gt; 中的“345”?

a_0、a_1 的结尾数字 + choice_4、choice_9 的子代是动态创建的,_[number] 中没有逻辑,每个下一个元素都加 1。

【问题讨论】:

    标签: php xml foreach simplexml


    【解决方案1】:

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

    例如遍历所有 a_* 元素,它只是

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

    输出:

    a_0
    a_1
    a_2
    

    然后您想再次迭代这些-&gt;type 子级。通过将一个foreach 放入另一个是在纯 PHP 中是可能的:

    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 检索数据。

    如果您还需要访问 &lt;a_*&gt; 元素,您需要拥有多个 foreach 的或您自己的迭代,但这是一个更我想说的高级主题会超出您的问题的范围。

    我希望到目前为止这对您有所帮助。另见SimpleXMLElement::children(),它也给了所有孩子(如第一个例子中的-&gt;games[0])。所有示例代码都可以通过a working, interactive online-demo 获得。

    【讨论】:

    • 我不确定 XPath 一般是否“像访问文件系统一样访问 XML 数据”,尽管我猜像这样一个相对简单的表达式很容易让人联想到的文件 glob。我可能会在某个地方查找它,但 XPath 可以评估像 //a_* 这样的部分通配符吗?
    • @IMSoP:文件系统比较是一个类比,并不完全相同。部分通配符在您概述时不起作用,它与字符串表达式一起使用,或者 - 可能在 PHP 中 - 将正则表达式匹配函数放在那里。
    • 好的,谢谢。总有一天我会花时间学习基础知识之外的 XPath :)
    • xpath 1.0 有时有点笨拙,但通常比 X foreaches 更好地使用,因此是一个很好的工具。
    【解决方案2】:

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

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

    【讨论】:

      【解决方案3】:

      您可以使用 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查看结果

      【讨论】:

      • 似乎将全部打印出来(包括节点名称)?或者也许我只是看错了小提琴。我想做的是能够通过单个 $value_vars 访问/迭代不同元素的值
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-06-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多