将问题分解为一个可重复的小例子:
$xml = <<<'XML'
<books>
<book><title>A Title</title></book>
<book><title> A Title </title></book>
</books>
XML;
$books = new SimpleXMLElement($xml);
echo "String compare:\n";
foreach ($books->xpath('//book[title="A Title"]') as $book) {
var_dump((string)$book->title);
}
输出:
String compare:
string(7) "A Title"
第二本书的标题包含前后空格,因此简单的字符串比较将无法匹配它。解决这个问题的一种方法是使用normalize-space()。此 Xpath 函数将用单个空格替换任何空格序列并删除前面/后面的空格。它的作用有点大,但在大多数情况下它应该无关紧要。
echo "\nwith normalize-space():\n";
foreach ($books->xpath('//book[normalize-space(title)="A Title"]') as $book) {
var_dump((string)$book->title);
}
输出:
with normalize-space():
string(7) "A Title"
string(11) " A Title "
现在它匹配两个标题,但它也会匹配 A Title 之类的东西。
另一种解决方案允许您进行更多控制,但需要 DOM。在 DOM 中,您可以将 PHP 函数注册为可从 XPath 表达式调用。这可以是现有功能或您自己的功能。你可以让trim() 可用:
$document = new DOMDocument();
$document->loadXML($xml);
$xpath = new DOMXpath($document);
$xpath->registerNamespace("php", "http://php.net/xpath");
$xpath->registerPhpFunctions(['trim']);
echo "\nCall back into PHP:\n";
$expression = '//book[php:functionString("trim", string(title)) = "A Title"]';
foreach($xpath->evaluate($expression) as $node) {
var_dump($xpath->evaluate('string(title)', $node));
}
使用您自己的回调函数,您可以执行任何操作,例如 RegEx 匹配或 unicode 字符串音译。