Как я могу использовать php для поиска нескольких ключевых слов в файле xml и вернуть содержащийся тег?

У меня есть такой файл xml, в котором хранятся субтитры к видео:

<videos>
    <video>
        <id>1</id>
        <enSub>Hello Foo! Good morning!</enSub>
        <cnSub>你好 Foo! 早上好!</cnSub>
    </video>
    <video>
        <id>2</id>
        <enSub>Hello Bar! Good afternoon!</enSub>
        <cnSub>你好 Bar! 下午好!</cnSub>
    </video>
</videos>

Я хочу выполнить поиск по определенным ключевым словам с помощью этого xml, например, я ввожу «hello moning» в текстовую область поиска, и результат поиска может найти элемент видео с идентификатором «1».

Я предполагаю, что с помощью php xpath можно найти только одно ключевое слово в файле xml, и он должен перебирать все дерево. Я не уверен, что смогу написать функцию с хорошей производительностью.

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

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

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

Я много гуглил. Это очень медленно, иногда я просто не могу получить доступ к Google, у себя дома в Китае. Я попробовал «поиск по нескольким ключевым словам xml» в качестве ключевых слов для поиска. Может быть, мой английский недостаточно умен, чтобы Google понял мои намерения. Я надеюсь, что вы, ребята, понимаете мой вопрос.

Большое спасибо!!


person Luke Chen    schedule 18.12.2013    source источник
comment
Спасибо! @Nouphal.M. Я был очень неосторожен, не проверил свои xml-теги. Но не волнуйтесь. В моих проектах все теги в порядке.   -  person Luke Chen    schedule 19.12.2013
comment
Не имеет отношения, но здесь у вас есть беспроблемный подход: fsockopen.com/php-programming/   -  person Chris Russo    schedule 17.08.2016


Ответы (3)


Пожалуйста, посмотрите мой пример кода ниже, чтобы узнать, как это сделать.

<?php
$xml = <<<XML
<videos>
    <video>
        <id>1</id>
        <enSub>Hello Foo! Good morning!</enSub>
        <cnSub>你好 Foo! 早上好!</cnSub>
    </video>
    <video>
        <id>2</id>
        <enSub>Hello Bar! Good afternoon!</enSub>
        <cnSub>你好 Bar! 下午好!</cnSub>
    </video>
</videos>
XML;
// Lowercase the XML so we can do a non-case-sensitive search.
$xml = strtolower($xml);
// Create a DOMDocument based on the xml.
$dom = new DOMDocument;
$dom->loadXML($xml);
// Create an xpath based on the dom document so we can search it.
$xpath = new DOMXpath($dom);
// Search for any video tag that contains the text good morning.
$nodes = $xpath->query('//video[contains(.,\'good morning\')]');
// Iterate all nodes
foreach($nodes as $node){
    // find the ID node and print its content.
    var_dump($xpath->query('id',$node)->item(0)->textContent);
}

-- Редактировать

Я перечитал ваш пост, и похоже, что вы используете ключевые слова, а не строки. Если это так, попробуйте этот фрагмент для размера:

<?php
$xml = <<<XML
<videos>
    <video>
        <id>1</id>
        <enSub>Hello Foo! Good morning!</enSub>
        <cnSub>你好 Foo! 早上好!</cnSub>
    </video>
    <video>
        <id>2</id>
        <enSub>Hello Bar! Good afternoon!</enSub>
        <cnSub>你好 Bar! 下午好!</cnSub>
    </video>
</videos>
XML;
// Lowercase the XML so we can do a non-case-sensitive search.
$xml = strtolower($xml);
// Create an DOMDocument based on the xml.
$dom = new DOMDocument;
$dom->loadXML($xml);
// Create an xpath based on the dom document so we can search it.
$xpath = new DOMXpath($dom);
// Define the search keywords
$searchKeywords = array('good','hello');
// Iterate all of them to make them into valid xpath
$searchKeywords = array_map(
    function($keyword){
        // Replace any single quotes with an escaped single quote.
        $keyword = str_replace('\'','\\\'',$keyword);
        return 'contains(.,\''.$keyword.'\')';
    },
    $searchKeywords
);
// Implode all the keywords using and, you could change this to be
// an"or" condition if you so desire.
$searchKeywords = implode(' and ',$searchKeywords);
// The search keywords now look like contains(.,'good') and contains(.,'hello')
// Search for any video tag that contains the text good morning.
$nodes = $xpath->query('//video['.$searchKeywords.']');
// Iterate all nodes
foreach($nodes as $node){
    // find the ID node and print its content.
    var_dump($xpath->query('id',$node)->item(0)->textContent);
}
person Kyle    schedule 18.12.2013
comment
Привет @Кайл! большое спасибо! Я проверил ваш код в песочнице php. Это работает очень хорошо! Я потратил час на изучение некоторых неизвестных мне функций. Спасибо! могу я спросить, как эта функция повлияет на производительность моего сервера хостинга php? Скажем, у меня 1000 пользователей и 1000 видео, и они ищут с помощью этой функции. Это сильно замедлит мой сервер? Совершенно не разбираюсь в производительности. может я недооцениваю свой хостинг php сервер? Спасибо! - person Luke Chen; 19.12.2013
comment
привет @Кайл! Не могли бы вы научить меня, что означает точка '.' в функции contrains()? Я просмотрел руководство, должна ли это быть строка, содержащая ключевое слово? - person Luke Chen; 19.12.2013
comment
Другой вопрос, что я загружаю файл xml. Как сделать нижний регистр всего xml-файла? Должен ли я сначала загрузить xml, а затем $dom->saveXML($dom)? Спасибо!! - person Luke Chen; 19.12.2013
comment
Производительность не должна иметь большого значения. Если вы беспокоитесь, почему бы не добавить 1000 видео, а затем использовать приложение, чтобы несколько раз попасть на ваш сервер. '.' означает текущий узел. Подробнее об этом можно узнать здесь: (w3schools.com/xpath/xpath_syntax.asp ). Что касается нижнего регистра всего xml-файла, вы можете сделать это либо на лету (как показано в моем примере), либо вы можете сделать это вручную с файлом перед его загрузкой на ваш сервер. - person Kyle; 19.12.2013
comment
Спасибо! @ Кайл Ты действительно помог мне! - person Luke Chen; 20.12.2013

Прежде всего, ваш xml запутан, открывающий и закрывающий теги должны совпадать. Вы можете использовать DomDOcument для управления xml.

$searchStr ="hello afternoon";
$searchArr = explode(" ",$searchStr);
$result = array();
$xmlData = "<videos>
    <video>
        <id>1</id>
        <enSub>Hello Foo! Good morning!</enSub>
        <cnSub>你好 Foo! 早上好!</cnSub>
    </video>
    <video>
        <id>2</id>
        <enSub>Hello Bar! Good afternoon!</enSub>
        <cnSub>你好 Bar! 下午好!</cnSub>
    </video>
</videos>";

$dom = new DOMDocument();
$dom->loadXML($xmlData);
foreach ($dom->documentElement->childNodes as $node) {
if($node->nodeType==1){
   $enSub = $node->getElementsByTagName('enSub')->Item(0)->nodeValue;
   $cnSub = $node->getElementsByTagName('cnSub')->Item(0)->nodeValue;
   $id = $node->getElementsByTagName('id')->Item(0)->nodeValue;
   foreach($searchArr as $key=>$val){
      $temp = array();
      if( strpos($enSub,$val) != false ){
          $temp[$id] = array(
             'id'=>$id,
             'enSub'=>$enSub,
             'cnSub'=>$cnSub
          );
          $result[$id]=$temp;
      }

   }
 }
}
echo "<pre>";
print_r($result);

Вы можете найти рабочую демонстрацию здесь

person Nouphal.M    schedule 18.12.2013
comment
Большое спасибо! @ Nouphal.M И спасибо за отличную песочницу php, я никогда этого не знал! Извините, я не могу принять два ответа, но Кайл помог мне точно определить идентификатор видео, выполнив поиск по ключевым словам как в cnSub, так и в enSub. - person Luke Chen; 19.12.2013

Думаю, вы могли бы использовать поисковый сервер, например ElasticSearch. Он использует Lucene для индексации любого контента. Затем индексированный контент можно запросить через JSON API.

Это, конечно, имеет смысл только тогда, когда вы постоянно работаете с большим объемом данных.

Другой подход состоял бы в том, чтобы проанализировать xml и создать массив, в котором каждый термин во вложенном теге является индексом. Тогда значение будет массивом, содержащим идентификаторы фильмов, у которых есть этот термин в соответствующем теге. По сути, вы создаете собственный простой индекс данных.

Затем вы можете запросить свой индекс следующим образом:

<?php

$index = array(
    'Hello' => array(1,3),
    'World' => array(1),
    'Good' => array(2),
    'Morning' => array(2),
    'Vietnam' => array(2,3),
);

$searchTerms = array('Hello', 'World');

$found = null;
foreach($searchTerms as $term){
    if(array_key_exists($term, $index)){
        if(is_null($found)){
            $found = $index[$term];
        } else {
            $found = array_intersect($found, $index[$term]);
        }
    } else {
        $found = array();
        break;
    }
}

print_r($found);

Основное преимущество этого подхода заключается в том, что вам нужно будет просмотреть XML-документ только один раз, имея при этом довольно быстрый поиск. Кстати, если вы хотите обрабатывать условия поиска с помощью ИЛИ вместо И, вы можете использовать array_merge и array_unique вместо array_intersect.

Где-то посередине можно было бы настроить реальную базу данных, такую ​​как MySQL, и выполнить описанный выше поиск в запросе. .

Это действительно зависит от того, чего вы хотите достичь.

person Christoph Grimmer-Dietrich    schedule 18.12.2013
comment
Спасибо! @Кристоф Гриммер-Дитрих. извините, я новичок в php и xml, раньше не использовал индекс. и ответ Кайла уже может сделать это. и я могу понять его коды. Все же разрешите поблагодарить вас! - person Luke Chen; 19.12.2013
comment
Нет проблем, @LukeChen. Может быть, кому-то еще мой ответ будет полезен. Поскольку SO посещает так много людей, это может быть не напрасно :-) - person Christoph Grimmer-Dietrich; 23.12.2013