Intereting Posts
Проверка того, содержит ли массив все элементы другого массива Понимание файлов PHP и вызовов AJAX Уведомление Firebase, которое не получено на устройстве при отправке через cURL / PHP Разрешены ли зарезервированные ключевые слова PHP в пространстве имен? (открытый, закрытый, дефолт) Как «читать» HTML-документ в PHP? Почему я не могу видеть исходный код с FF, когда у меня есть это утверждение if? Как НЕ автозагрузить класс в php? Где я могу получить полный список событий Laravel (выпущенных основными библиотеками)? Как декодировать строку base64 (gif) в изображение в PHP / HTML Проверка почтового индекса Соединенного Королевства (GB) без регулярного выражения Очень конкретный запрос MySQL, который я хочу улучшить Почему я получаю фатальную ошибку при вызове конструктора родителя? Как правильно настроить переменную среды PHP для запуска команд в Git Bash Пароль «солей». Правильно ли я это делаю? PHP Предупреждение: mysql_query () ожидает, что параметр 1 будет строкой

нечувствительный к регистру 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"; 

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

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

Я пробовал:

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

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

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

Во-первых, есть очевидная оговорка, которую Чарльз указал в своем комментарии к этому вопросу. Тогда есть логика того, как вы пытаетесь сопоставить текстовые значения.


В текстовой форме вы в настоящее время спрашиваете: « содержит ли текст нижний регистр ключевого слова? » Это не то, что вы хотите спросить. Вместо этого спросите: « содержит ли нижний регистр ключевое слово в нижнем регистре? » Перевод (pardon the pun), который возвращается в XPath-land:

(Примечание: усеченные алфавиты для удобочитаемости)

 //line[contains(translate(text(),'ABC...Z','abc...z'),'chicago')] 

Вышеприведенный текст уменьшает текст, содержащийся в узле line проверяет, содержит ли он (нижний текст) ключевое слово chicago .


И теперь для обязательного фрагмента кода (но на самом деле, вышеупомянутая идея – это то, что вам действительно нужно забрать домой):

 $xml = simplexml_load_file($data); $search = strtolower($keyword); $nodes = $xml->xpath("//line[contains(translate(text(), 'ABCDEFGHJIKLMNOPQRSTUVWXYZ', 'abcdefghjiklmnopqrstuvwxyz'), '$search')]"); echo 'Got ' . count($nodes) . ' matches!' . PHP_EOL; foreach ($nodes as $node){ echo $node . PHP_EOL; } 

Редактировать после комментария дижона

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

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

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

Поскольку 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 ). Надеюсь, вы сможете выяснить, как получить доступ к атрибуту name .

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

В качестве альтернативы / добавленной опции для использования функций XPath вы можете использовать любую PHP-функцию с PHP5.3, включая самоопределяемую, в выражениях XPath при использовании DOM . Я не уверен, что он доступен в 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')]"); 

Таким образом, вы сравниваете строчные буквы: lowercase