关于xml:php xpath查询,根据重复子节点中的值获取父节点

php xpath query to get parent node based on value in repeating child nodes

我有一个XML文件,其结构如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
<pictures>
    <picture>
       
        <description></description>
        <facts>
            <date></date>
            <place>Unites States</place>
        </facts>
        <people>
            <person>John</person>
            <person>Sue</person>
        </people>
    </picture>
    <picture>
       
        <description></description>
        <facts>
            <date></date>
            <place>Canada</place>
        </facts>
        <people>
            <person>Sue</person>
            <person>Jane</person>
        </people>
    </picture>
    <picture>
       
        <description></description>
        <facts>
            <date></date>
            <place>Canada</place>
        </facts>
        <people>
            <person>John</person>
            <person>Joe</person>
            <person>Harry</person>
        </people>
    </picture>
<pictures>

在一个案例中,我需要在place="canada"中搜索图片。我有一个XPath可以做到这一点,比如:

1
2
$place ="Canada";
$pics = ($pictures->xpath("//*[place='$place']"));

这将拉动整个"图片"节点,因此我可以显示标题、描述等。我还有另一个需要找到所有图片,其中person=$person。我使用与上面相同的类型查询:

1
2
$person ="John";
$pics = ($pictures->xpath("//*[person='$person']"));

在本例中,查询显然知道John有两张图片,但我没有得到其他节点的任何值。我猜这和重复的子节点有关系,但是我不知道如何重新构造xpath来为每个我匹配的人提取所有图片节点。我尝试使用属性而不是值(并相应地修改了查询),但得到了相同的结果。有人能告诉我这里缺少什么吗?


让我们先替换变量。这就把PHP从图片中去掉了。问题只是正确的xpath表达式。

//*[place='Canada']

匹配具有子元素节点place和文本内容Canada的任何元素节点。

这是facts元素节点,而不是picture

获取图片节点略有不同:

//picture[facts/place='Canada']

这将选择任何深度与条件匹配的图片节点。

picture[facts/place='Canada']

将返回与所提供的XML相同的结果,但更具体,只匹配作为document元素子级的picture元素节点。

现在验证people节点大致相同:

picture[people/person="John"]

您甚至可以将这两个条件结合起来:

picture[facts/place="Canada" and people/person="John"]

下面是一个小演示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
$element = new SimpleXMLElement($xml);

$expressions = [
  '//*[place="Canada"]',
  '//picture[facts/place="Canada"]',
  'picture[facts/place="Canada"]',
  'picture[people/person="John"]',
  'picture[facts/place="Canada" and people/person="John"]',
];

foreach ($expressions as $expression) {
  echo $expression,"
"
, str_repeat('-', 60),"
"
;
  foreach ($element->xpath($expression) as $index => $found) {
     echo '#', $index,"
"
, $found->asXml(),"
"
;
  }
  echo"
"
;
}

提示:在xpath表达式中使用dyamic值。xpath 1.0中的字符串文本不支持任何类型的转义。变量中的引号可能会破坏表达式。看看这个答案。