Разбивка вопроса на небольшой воспроизводимый пример:
$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 или транслитерацию строк в Юникоде.