如何使用PHP获取XML中所有祖先节点的id?

时间:2018-03-26 22:06:05

标签: php xml

我有一个大的XML文件,看起来像这样:

<envelope>
  <headers>
  ...
  </headers>
<data>
  <Channel Id="303131" created="2016-06-02T14:01:00" modified="2016-06-02T14:01:00">
  <Fields />
  <Links>
    <ChannelNodes type="ChannelChannelNodes">
 ***  <ChannelNode Id="318630" created="2016-07-15T14:44:00" modified="2016-07-15T14:44:00" Index="0" LinkId="338254">
        <Fields />
        <Links>
          <ChannelNodes type="ChannelNodeChannelNodes">
 ***        <ChannelNode Id="303152" created="2016-06-02T14:29:00" modified="2016-08-31T11:14:00" Index="0" LinkId="338256">
              <Fields />
              <Links>
                <ChannelNodes type="ChannelNodeChannelNodes">
                  <ChannelNode Id="303155" created="2016-06-02T14:29:00" modified="2016-07-08T09:50:00" Index="0" LinkId="311083">
                    <Fields />
                    <Links>
                      <ChannelNodes type="ChannelNodeChannelNodes">
 ***                    <ChannelNode Id="303157" created="2016-06-02T14:29:00" modified="2016-08-26T14:08:00" Index="0" LinkId="311086">
                          <Fields />
                          <Links>
                            <ChannelNodes type="ChannelNodeChannelNodes">
                              <ChannelNode Id="303158" created="2016-06-02T14:29:00" modified="2016-08-26T14:09:00" Index="0" LinkId="311087">
                                <Fields />
                                <Links />
                              </ChannelNode>
 ***                          <ChannelNode Id="303159" created="2016-06-02T14:30:00" modified="2016-08-26T14:09:00" Index="1" LinkId="311088">
                                <Fields />
                                <Links />
                              </ChannelNode>
                              <ChannelNode Id="303160" created="2016-06-02T14:30:00" modified="2016-08-26T14:09:00" Index="2" LinkId="311089">
                                <Fields />
                                <Links />
                              </ChannelNode>
                            </ChannelNodes>
                          </Links>
                        </ChannelNode>
                        <ChannelNode Id="303161" created="2016-06-02T14:30:00" modified="2016-08-26T14:09:00" Index="1" LinkId="311090">
                          <Fields />
                          <Links />
                        </ChannelNode>
                        <ChannelNode Id="303162" created="2016-06-02T14:30:00" modified="2016-08-26T14:10:00" Index="2" LinkId="311091">
                          <Fields />
                          <Links />
                        </ChannelNode>
...etc

我需要找到一种方法来列出给定id的所有祖先节点的ID(我不确定我是否使用了正确的术语)。例如。我的输入可能是$ id = 303159,我的输出应该是$ ids = [303157,303152,318630](所有相关的行标有***)。

很可能输入id可以在不同深度的同一xml文件中的不同位置找到。例如,在上面的示例中,输入id有三个祖先,但它可能在一个地方有1个祖先,在同一个文件中有另一个地方有4个祖先。但是我需要的输出只是一个所有祖先的数组(1个祖先+ 4个祖先会产生5个元素的数组)。

我想我可以这样做:

$arr = simplexml_load_string($xml, null, LIBXML_NOCDATA);

只需使用许多foreach语句,搜索正确的ID。 问题在于它感觉不对,因为我确定还有另一种方法可以做到这一点,因为xml的深度可以随时改变(现在最深层是4个节点,但它可能是8个节点)在将来或任何其他数字)。

修改

这是我目前的解决方案。它适用于我当前的数据,但它不是一个好的解决方案。

$arr = simplexml_load_string($xml, null, LIBXML_NOCDATA);
foreach($arr->data->Channel as $cn1) {
    $result[(string) $cn1->attributes()] = "allt";
    foreach ($cn1->Links->ChannelNodes->ChannelNode as $cn2) {
    $result[(string) $cn2->attributes()][] = (string) $cn1->attributes();
        foreach ($cn2->Links->ChannelNodes->ChannelNode as $cn3) {
            $result[(string) $cn3->attributes()][] = (string) $cn1->attributes();
            $result[(string) $cn3->attributes()][] = (string) $cn2->attributes();
            foreach ($cn3->Links->ChannelNodes->ChannelNode as $cn4) {
                $result[(string) $cn4->attributes()][] = (string) $cn1->attributes();
                $result[(string) $cn4->attributes()][] = (string) $cn2->attributes();
                $result[(string) $cn4->attributes()][] = (string) $cn3->attributes();
                foreach ($cn4->Links->ChannelNodes->ChannelNode as $cn5) {
                    $result[(string) $cn5->attributes()][] = (string) $cn1->attributes();
                    $result[(string) $cn5->attributes()][] = (string) $cn2->attributes();
                    $result[(string) $cn5->attributes()][] = (string) $cn3->attributes();
                    $result[(string) $cn5->attributes()][] = (string) $cn4->attributes();
                    foreach ($cn5->Links->ChannelNodes->ChannelNode as $cn6) {
                        $result[(string) $cn6->attributes()][] = (string) $cn1->attributes();
                        $result[(string) $cn6->attributes()][] = (string) $cn2->attributes();
                        $result[(string) $cn6->attributes()][] = (string) $cn3->attributes();
                        $result[(string) $cn6->attributes()][] = (string) $cn4->attributes();
                        $result[(string) $cn6->attributes()][] = (string) $cn5->attributes();
                        foreach ($cn6->Links->ChannelNodes->ChannelNode as $cn7) {
                            $result[(string) $cn7->attributes()][] = (string) $cn1->attributes();
                            $result[(string) $cn7->attributes()][] = (string) $cn2->attributes();
                            $result[(string) $cn7->attributes()][] = (string) $cn3->attributes();
                            $result[(string) $cn7->attributes()][] = (string) $cn4->attributes();
                            $result[(string) $cn7->attributes()][] = (string) $cn5->attributes();
                            $result[(string) $cn7->attributes()][] = (string) $cn6->attributes();
                        }
                    }
                }
            }
        }
    }
}

1 个答案:

答案 0 :(得分:0)

您只需要一个反向路径xpath查询。

$lookForID = 303159;

$sXML = simplexml_load_string($xml, null, LIBXML_NOCDATA);

$ancestorIdNodes = $sXML->xpath(
    "//ChannelNode[@Id=\"{$lookForID}\"]/ancestor::ChannelNode/@Id"
);

$ancestorIds = [];
foreach($ancestorIdNodes as $node) {
    $ancestorIds[] = (string) $node['Id'];
}

// $ancestorIds is an array of IDs you are looking for.

实际的xpath字符串可以读作:获取任何ChannelNode元素的Id属性,这些元素是树中Id属性等于303159的任何ChannelNode的祖先。