нечувствительный к регистру поиск xpath в php

у меня есть xml-файл, как это:

<volume name="Early">
<book name="School Years">
<chapter number="1">
<line number="1">Here's the first line with Chicago in it.</line>
<line number="2">Here's a line that talks about Atlanta</line>
<line number="3">Here's a line that says chicagogo </line>
</chapter>
</book>
</volume>

Я пытаюсь выполнить простой поиск по ключевым словам с помощью PHP, который находит Слово и отображает строку, в которой оно было. У меня это работает

$xml = simplexml_load_file($data);
$keyword = $_GET['keyword'];
$kw=$xml->xpath("//line[contains(text(),'$keyword')]");
...snip...

echo $kw[0]." is the first returned item";

однако, используя эту технику, пользователь должны поиск "Чикаго", а не "Чикаго", или поиск ничего не вернет.

Я понимаю, что мне нужно использовать функцию перевода, но все мои проб и ошибок было напрасно.

Я попробовал:

$upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
$lower = "abcdefghijklmnopqrstuvwxyz";
$kw = $xml->xpath("line[contains(text(),'translate('$keyword','$upper','$lower'))]");

но ничего не работает. есть советы?

3 ответов


рекомендация Гордона использовать функцию PHP из XPath окажется более гибкой, если вы решите использовать ее. Однако, вопреки его ответу,translate строковые функции и доступно в XPath 1.0, так что это означает, что вы можете использовать его; ваша проблема как.


в словесной форме вы спрашиваете:"содержит ли текст строчную форму ключевого слова?Дижона

внутри foreach вы можете получить доступ к номеру строки, номеру главы и названию книги, например под.

номер строки -- это просто атрибут на <line> элемент, который делает доступ к его супер-легко. Существует два способа доступа к SimpleXML:$node['number'] или $node->attributes()->number (Я предпочитаю первое).

номер главы -- чтобы добраться до этого, как вы правильно сказали, нам нужно пройти по дереву. Если бы мы использовали классы DOM, у нас был бы удобный $node->parentNode свойство, ведущее нас прямо к <chapter> (так как это непосредственный предок нашего <line>). SimpleXML не имеет такого удобного свойства, но мы можем использовать относительный запрос XPath для его получения. The родительская ось позволяет нам пройти вверх по дереву.

С xpath() возвращает массив, который мы можем обмануть и использовать current() для доступа к первому (и единственному) элементу в массиве, возвращенному из него. Тогда это просто вопрос доступа к number атрибут, как указано выше.

// In the near future we can use: current(...)['number'] but not yet
$chapter = current($node->xpath('./parent::chapter'))->attributes()->number;

название книги -- процесс ибо это то же самое, что и доступ к номеру главы. Относительный запрос XPath из <line> можно использовать оси предка как ./ancestor::book (или ./parent:chapter/parent::book). Надеюсь, вы можете выяснить, как получить доступ к его


см. ответ салата о том, как это сделать с помощью SimpleXml и translate().

в качестве альтернативной / добавленной опции для использования функций XPath вы можете использовать любую функцию PHP с PHP5.3, включая self defined, в выражениях XPath при использовании дом. Я не уверен, что то же самое доступно в SimpleXml.

// create a DOMDocument and load your XML string into it
$dom = new DOMDocument;
$dom->loadXML($xml);

// create a new Xpath and register PHP functions as XPath functions
$xPath = new DOMXPath($dom);
$xPath->registerNamespace("php", "http://php.net/xpath");
$xPath->registerPHPFunctions();

// Setup the query
$keyword = 'chicago';
$q = "//line[php:functionString('stripos', text(), '$keyword')]";
$nodes = $xPath->query($q);

// Iterate the resulting NodeList
foreach($nodes as $node) {
    echo $node->nodeValue, PHP_EOL;
}

выводится

Here's the first line with Chicago in it.
Here's a line that says chicagogo

дополнительные сведения см. В разделе @ salathes запись в блоге и в PHP Руководство.


Я что-то пропустил... но вот еще один подход, который ИМХО-проще. Как насчет использования PHP strtolower() перед загрузкой XML в SimpleXML через simplexml_load_string()?

IE

$xml = simplexml_load_string(strtolower(file_get_contents($xml_file_path)));
$keyword = strtolower($_GET['keyword']); //Make sure you sanitize this!
$kw = $xml->xpath("//line[contains(text(),'$keyword')]");

таким образом, вы сравниваете нижний регистр:: нижний регистр