У меня много XML-файлов, и я должен искать в этих файлах строку (подробно, которая будет не слишком сложным регулярным выражением).
С результатами я хочу получить xpath узла, в котором находится строка, то есть:
pattern = /home|house/ files: file1.xml, file2.xml etc
Результаты:
"home" in file1.xml, xpath: //root/cars/car[2] "house" in file2.xml, xpath: //root[1]/elemA[2][@attribute1='first']
Как я могу достичь этого? Я могу использовать PHP, python, Javascript, VIM-плагин (потому что я уже работал с ними)
В PHP: glob
файлы XML, xpath
все узлы, preg_match_all
их текст и, если совпадения, получить xpath узлов с getNodePath()
и вывести его:
$pattern = '/home|house|guide/iu'; foreach (glob('data/*.xml') as $file) { foreach (simplexml_load_file($file)->xpath('//*') as $node) { if (!preg_match_all($pattern, $node, $matches)) continue; printf( "\"%s\" in %s, xpath: %s\n", implode('", "', $matches[0]), basename($file), dom_import_simplexml($node)->getNodePath() ); } }
Результат (пример):
"Guide" in iana-charsets-2013-03-05.xml, xpath: /*/*[7]/*[158]/*[4] "Guide" in iana-charsets-2013-03-05.xml, xpath: /*/*[7]/*[224]/*[2] "Guide" in iana-charsets-2013-03-05.xml, xpath: /*/*[7]/*[224]/*[4] "guide" in rdf-dmoz.xml, xpath: /*/*[4]/d:Description "guide" in rdf-dmoz.xml, xpath: /*/*[5]/d:Description
Хороший вопрос кстати.
Поиск:
//*[contains('home') or contains('house')]
В PHP:
Используйте DOMDocument & DOMXPath, а затем просто вызовите DOMNode::getNodePath()
в результате совпадений.
Если вам действительно нужно регулярное выражение вместо этих совпадений раньше, то в DOMDocument от php есть только функции XPATH 1.0, но вы можете добавить функциональность DOMXPath, добавив определенную пользователем функцию с помощью DOMXPath::registerPhpFunctions
Взрыв чего-то быстро, без большой обработки ошибок:
function xpathregexmatch($nodelist,$regex){ foreach($nodelist as $node){ if( $node instanceof DOMText && preg_match($regex,$node->nodeValue)) return true; } return false; } foreach(glob('*.xml') as $file){ $d = new DOMDocument(); $d->load($file); $x = new DOMXPath($d); $x->registerNamespace("php", "http://php.net/xpath"); $x->registerPHPFunctions('xpathregexmatch'); $matches = $x->query('//*[php:function("xpathregexmatch",text(),"/house|home/")]'); if($matches->length){ foreach($matches as $node){ echo $file. ':'.$node->getNodePath().PHP_EOL; } } }
php simplexml:
$xml=simplexml_load_string("file1.xml"); foreach ($xml->cars->car[2] as $car) { // do sth with $car }
Побольше, уточните свой вопрос, пожалуйста.