PHP/XPATH - 查找父级的前一个 sibling 并获取其子级

标签 php xml xpath

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

假设我有一个名为 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),但我根本不知道该怎么做。

任何帮助都会很棒。

谢谢。

最佳答案

要获取最近的前一个同级,请使用此 XPath 查询:

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

您需要将谓词设置为 1,以便选择最近的 sibling 。否则,您将始终获得第一个同级(例如,如果删除 [1] 谓词,您将获得两个 BBB< 的 AAA 元素CCC)

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

$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

关于PHP/XPATH - 查找父级的前一个 sibling 并获取其子级,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49247433/

相关文章:

html - 在 XPath 中获取(文本)

php - 在回调中使用 yield?

python - 使用 ElementTree 解析 XML

xpath - VTD 2.13 发现使用节点值条件评估 xpath 的错误节点

php - Magento 本地 block 不会覆盖

xml - Go XML chardata 打印空行

java - 我想找到以 <br> 分隔的日期的 xpath

javascript - 如何从jquery对象中删除元素

php - PDO 中带有 mysql_fetch_row 的 if 语句

php - 使用 php/mysql 进行简单的 php 分页或 css 分页