dtgv52982 2018-03-13 02:35
浏览 31
已采纳

PHP / XPATH - 找到父母的先知和兄弟,并获得其“儿童”

I've been trying to figure this our for days, but I simply cannot seem to get it to work.

Let's say I have an XML file named test.xml like this:

<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>

From PHP, I use SimpleXMLElement to find the node with text 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)

Now, I'd like to find the preceding-sibling node of the parent, and get the child nodes' values like A (AAA), but I simply can't figure out how to do so.

Any help would be great.

Thanks.

  • 写回答

2条回答 默认 最新

  • dongyi5817 2018-03-13 03:48
    关注

    To get the nearest preceding sibling, use this XPath query:

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

    You need to set the predicate to 1 so as to pick the nearest of the siblings. Otherwise you'd always get the first sibling (for example, if you remove the [1] predicate, you'll get the AAA element for both BBB and CCC)

    Note that the wildcards are not necessary since you presumably already know what the tags are.

    $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

    Result

    A (AAA)
    B (BBB)

    To further illustrate the need to use the predicate, take a look at this:

    $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);
    

    Result

    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)
    

    See how, no matter which element you select with the query, the farthest sibling is always first in the list (and the closest the last)? So, to simulate using the predicate, you could also get the closest sibling simply picking the last element in the array (notice there's no [1] predicate):

    $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

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥15 R语言卸载之后无法重装,显示电脑存在下载某些较大二进制文件行为,怎么办
  • ¥15 java 的protected权限 ,问题在注释里
  • ¥15 这个是哪里有问题啊?
  • ¥15 关于#vue.js#的问题:修改用户信息功能图片无法回显,数据库中只存了一张图片(相关搜索:字符串)
  • ¥15 texstudio的问题,
  • ¥15 spaceclaim模型变灰色
  • ¥15 求一份华为esight平台V300R009C00SPC200这个型号的api接口文档
  • ¥15 字符串比较代码的漏洞
  • ¥15 欧拉系统opt目录空间使用100%
  • ¥15 ul做导航栏格式不对怎么改?