【问题标题】:Get xpath from search result of a specific regex pattern in a bunch of xml files从一堆 xml 文件中特定正则表达式模式的搜索结果中获取 xpath
【发布时间】:2013-02-21 23:25:12
【问题描述】:

我有很多 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 python xml regex xpath


    【解决方案1】:

    搜索:

     //*[contains('home') or contains('house')]
    

    在 PHP 中:

    使用 DOMDocument 和 DOMXPath,然后在结果匹配上调用 DOMNode::getNodePath()

    如果你真的需要一个正则表达式而不是之前的那些匹配,php 的 DOMDocument 只有 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;
                    }
            }
    }
    

    【讨论】:

    • 谢谢,我知道了!非常有帮助。我会尽力做到并让你知道!
    • 你也可以直接使用functionStringpreg_match()来代替xpathregexmatch()函数。
    • @salathe: 好点,总是忘记functionString... 但是$x->query('//*[php:functionString("preg_match","/wh[ab]t/",text())]');$x->query('//*[php:functionString("preg_match","/wh[ab]t/",.)]'); 也选择所有父节点,因为它可能会查看->textContent...
    • @Wrikken 不,这是因为preg_match() 返回 0 或 1(或 false);如果沿着这条路线走,您需要检查谓词内的返回值://*[php:functionString("preg_match", "/house|home/", text()) = "1"](或疯狂使用[boolean(number(php:functionString(…)))])。
    • 啊。很高兴我今天遇到了你……是的,少了类型的杂耍……//*[php:functionString("preg_match","/wh[ab]t/",text()) = "1"] 工作了 ;)
    【解决方案2】:

    在 PHP 中:glob XML 文件,xpath 所有节点,preg_match_all 其文本,如果匹配,则使用 getNodePath() 获取节点的 xpath 并输出:

    $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
    

    顺便说一句,好问题。

    【讨论】:

    • 接受了,因为它是最简单的,但@Wrikken 的回答也很好!
    • 是的,他的回答也很好。两者一起应该会给未来的用户留下一些好的启发。
    【解决方案3】:

    php simplexml:

    $xml=simplexml_load_string("file1.xml");
    foreach ($xml->cars->car[2] as $car) {
        // do sth with $car
    }
    

    如需更多信息,请更具体地回答您的问题。

    【讨论】:

    • 请仔细阅读,我没有xpath,我想从搜索结果中得到它
    猜你喜欢
    • 2021-11-09
    • 1970-01-01
    • 2023-01-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多