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

но ничто, кажется, не работает. какие-либо подсказки?

6
задан dijon 13 July 2010 в 16:01
поделиться

2 ответа

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

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


В текстовой форме вы спрашиваете: "содержит ли текст строчную форму ключевого слова?" Это не совсем то, что вы хотите спросить. Вместо этого спросите: "содержит ли строчный текст строчную форму ключевого слова?" Перевод (простите за каламбур) этого вопроса в страну XPath будет выглядеть следующим образом:

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

//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;
}

Edit after dijon's comment

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

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

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

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

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

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

8
ответ дан 10 December 2019 в 00:31
поделиться

См. Ответ 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.

2
ответ дан 10 December 2019 в 00:31
поделиться
Другие вопросы по тегам:

Похожие вопросы: