【问题标题】:PHP/XPATH - Find PRECEDING-SIBLING of PARENT and get its' CHILDPHP/XPATH - 找到 PARENT 的 PRECEDING-SIBLING 并获取它的 CHILD
【发布时间】:2018-03-13 02:35:03
【问题描述】:

几天来我一直在尝试解决这个问题,但我似乎无法让它发挥作用。

假设我有一个名为 test.xml 的 XML 文件,如下所示:

<root>
    <itemList>
        <item>
            <name>A</name>
            <type>AAA</type>
        </item>
        <item>
            <name>B</name>
            <type>BBB</type>
        </item>
        <item>
            <name>C</name>
            <type>CCC</type>
        </item>
    </itemList>
</root>

在 PHP 中,我使用 SimpleXMLElement 来查找带有文本 BBB 的节点。

<?php 
$xmlStr = file_get_contents('test.xml');
$xml = new SimpleXMLElement($xmlStr);
$res = $xml->xpath('//type[contains(text(), "BBB")]/parent::*');

echo "{$res[0]->name} ({$res[0]->type})";
// Result: B (BBB)

现在,我想找到parentpreceding-sibling 节点,并获取child 节点的值,例如A (AAA),但我根本不知道该怎么做。

任何帮助都会很棒。

谢谢。

【问题讨论】:

    标签: php xml xpath


    【解决方案1】:

    要获取最近的前同级,请使用以下 XPath 查询:

    //type[contains(text(), "BBB")]/parent::item/preceding-sibling::item[1]
    

    您需要将谓词设置为 1 以便选择最近的兄弟姐妹。否则你总是会得到第一个兄弟(例如,如果你删除[1] 谓词,你会得到BBBCCCAAA 元素)

    请注意,通配符不是必需的,因为您可能已经知道标签是什么。

    $xml = "<root>
        <itemList>
            <item>
                <name>A</name>
                <type>AAA</type>
            </item>
            <item>
                <name>B</name>
                <type>BBB</type>
            </item>
            <item>
                <name>C</name>
                <type>CCC</type>
            </item>
        </itemList>
    </root>";
    
    $xml = new SimpleXMLElement($xml);
    
    $res = $xml->xpath('//type[contains(text(), "BBB")]/parent::item/preceding-sibling::item[1]');
    echo "{$res[0]->name} ({$res[0]->type})".PHP_EOL;
    
    $res = $xml->xpath('//type[contains(text(), "CCC")]/parent::item/preceding-sibling::item[1]');
    echo "{$res[0]->name} ({$res[0]->type})";
    

    Demo

    结果

    A (AAA)
    B (BBB)

    为了进一步说明使用谓词的必要性,看看这个:

    $xml = "<root>
        <itemList>
            <item>
                <name>A</name>
                <type>AAA</type>
            </item>
            <item>
                <name>B</name>
                <type>BBB</type>
            </item>
            <item>
                <name>C</name>
                <type>CCC</type>
            </item>
            <item>
                <name>C</name>
                <type>DDD</type>
            </item>
        </itemList>
    </root>";
    
    $xml = new SimpleXMLElement($xml);
    
    $res = $xml->xpath('//type[contains(text(), "DDD")]/parent::item/preceding-sibling::item');
    var_dump($res);
    

    结果

    array (size=3)
      0 => 
        object(SimpleXMLElement)[2]
          public 'name' => string 'A' (length=1)
          public 'type' => string 'AAA' (length=3)
      1 => 
        object(SimpleXMLElement)[3]
          public 'name' => string 'B' (length=1)
          public 'type' => string 'BBB' (length=3)
      2 => 
        object(SimpleXMLElement)[4]
          public 'name' => string 'C' (length=1)
          public 'type' => string 'CCC' (length=3)
    

    看看,无论您使用查询选择哪个元素,最远的兄弟元素总是在列表中排在第一位(最近的排在最后一个)?因此,为了模拟使用谓词,您还可以简单地选择数组中的最后一个元素来获取最近的兄弟(注意没有[1] 谓词):

    $res = $xml->xpath('//type[contains(text(), "DDD")]/parent::item/preceding-sibling::item');
    $total = count($res);
    echo "{$res[$total - 1]->name} ({$res[$total - 1]->type})".PHP_EOL;
    

    Demo

    【讨论】:

    • 非常感谢您。这正是我所需要的。 :)
    • @LilisSkyremix 没问题的人。我添加了另一个示例以进一步阐明对谓词的需求以及替代方法。祝你好运。
    【解决方案2】:

    查看演示https://implode.io/q9OOSC

    $xmlStr = <<<XML
    <root>
        <itemList>
            <item>
                <name>A</name>
                <type>AAA</type>
            </item>
            <item>
                <name>B</name>
                <type>BBB</type>
            </item>
            <item>
                <name>C</name>
                <type>CCC</type>
            </item>
        </itemList>
    </root>
    XML;
    
    $xml = new SimpleXMLElement($xmlStr);
    
    $res = $xml->xpath('//type[contains(text(), "BBB")]/parent::*/preceding-sibling::*');
    
    echo "{$res[0]->name} ({$res[0]->type})";
    

    【讨论】:

      猜你喜欢
      • 2018-06-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-03-02
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多