首页 > 解决方案 > PHP xpath 查询中的空格(新的 SimpleXMLElement)

问题描述

我收到一个 XML 输出,并使用新的 SimpleXMLElement 对其进行转换。输出是一个数组。所以 XML 元素是 $xml。

print_r($xml->xpath('categories[categories_name="Toners"]/childs/categories[categories_name="Color LaserJet"]'));

在第二个 [categories_name] 中,值在字符串中有一个空格。由于空间的原因,出现了问题。我没有返回任何信息,如果我用另一个没有空格的现有值删除该值,我会得到我想要的信息。

我能做些什么?

标签: phpxmlxpath

解决方案


将问题分解为一个可重复的小示例:

$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 字符串音译。


推荐阅读