我有一个XML文件,其结构如下:
<pictures>
<picture>
<title></title>
<description></description>
<facts>
<date></date>
<place>Unites States</place>
</facts>
<people>
<person>John</person>
<person>Sue</person>
</people>
</picture>
<picture>
<title></title>
<description></description>
<facts>
<date></date>
<place>Canada</place>
</facts>
<people>
<person>Sue</person>
<person>Jane</person>
</people>
</picture>
<picture>
<title></title>
<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可以做到这一点,例如:
$place = "Canada";
$pics = ($pictures->xpath("//*[place='$place']"));
这会拉取整个"图片"节点,这样我就可以显示标题、描述等。我还有一个需要找到person=$person的所有图片。我使用与上面相同的类型查询:
$person = "John";
$pics = ($pictures->xpath("//*[person='$person']"));
在这种情况下,查询显然知道有两张John的照片,但我没有得到其他节点的任何值。我猜这与重复的子节点有关,但我不知道如何重组XPath,为每个匹配的人提取所有的图片节点。我尝试使用属性而不是值(并相应地修改了查询),但得到了相同的结果。有人能告诉我这里缺了什么吗?
让我们先替换变量。这就把PHP排除在外了。问题只是正确的XPath表达式。
//*[place='Canada']
将具有子元素节点CCD_ 2的任何元素节点与文本内容CCD_。
这是facts
元素节点,而不是picture
。
获取图片节点略有不同:
//picture[facts/place='Canada']
这将选择与条件匹配的ANY DEPTH处的ANY图片节点。
picture[facts/place='Canada']
将使用所提供的XML返回相同的结果,但更具体,并且仅与作为文档元素的子级的picture
元素节点匹配。
现在验证people
节点大致相同:
picture[people/person="John"]
你甚至可以将两个条件结合起来:
picture[facts/place="Canada" and people/person="John"]
这里有一个小演示:
$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, "'n", str_repeat('-', 60), "'n";
foreach ($element->xpath($expression) as $index => $found) {
echo '#', $index, "'n", $found->asXml(), "'n";
}
echo "'n";
}
提示:在XPath表达式中使用dyamic值。XPath 1.0中的字符串文字不支持任何类型的转义。变量中的引号可能打断您的表达式。看看这个答案。