当前位置: 首页 > 知识库问答 >
问题:

xpath让我失望

唐沈义
2023-03-14

我有一个xml结构:

<Articles>

    <Article ID="111">
        <author>Peter Paul</author>
        <pubDate>01/01/2015</pubDate>  
        <Translations>
            <lang1>English</lang1>
            <lang2>French</lang2>
            <lang3>Arab</lang3>
            <lang3>Chinese</lang3>
        </Translations>
    </Article>

    <Article ID="222">
        <author>Monkey Rice</author>
        <pubDate>01/01/2016</pubDate>  
        <Translations>
            <lang1>English</lang1> 
        </Translations>
    </Article>

    <Article ID="333">
        <author>John Silas</author>
        <pubDate>01/01/2017</pubDate>  
        <Translations>
            <lang1>English</lang1>
            <lang2>French</lang2>
            <lang3>Arab</lang3>
            <lang3>Chinese</lang3>
        </Translations>
    </Article>

</Articles>

我创建了一个AddRecordByInfoMatch()方法,只要存在匹配项,该方法就会尝试将新节点添加到任意给定ID中:

function AddRecordByInfoMatch($ParentID, $Info_1, $Info_2, $Info_3, array $Record){

            $xml = new SimpleXMLElement(blabla.xml);
            $result = $xml->xpath("//*[@ID='$ParentID']");      //get the article ID


            if(!empty($result)){
                foreach($result[0] as $key => $value){

                    $noofChild = count($value);
                    //three info match may lakely be within 3 sub-nodes 
                    if($noofChild >= 3){

                        $query = "//*[node()[contains(text(), \"$Info_1\")] and node()[contains(text(), \"$Info_2\")] and node()[contains(text(), \"$Info_3\")]]";

                        $data = $xml->xpath($query);

                        if(!empty($data[0]){
                                foreach ($Record as $nodname => $val){     
                                    $data[0]->addChild($nodname, $val);   
                                }
                        }    
                    }
                }
            }
}

考虑到ID=333,我这样测试运行它:

XMLAddRecordByInfoMatch(333, "English", "French", "Chinese", array( 
            "syntax" => irrelevant,
            "adjectives" => None,
            "verbs" => 2,
            "prepositions" => 5 
        ));

不幸的是,输出;显示时,将新记录添加到ID为111的文章中以获得:

xml prettyprint-override">...
<Article ID="111">
        <author>Peter Paul</author>
        <pubDate>01/01/2015</pubDate>  
        <Translations>
            <lang1>English</lang1>
            <lang2>French</lang2>
            <lang3>Arab</lang3>
            <lang3>Chinese</lang3>

            <syntax>irrelevant</syntax>
            <adjectives>None</adjectives>
            <verbs>2</verbs>
            <prepositions>5</prepositions>

        </Translations>
    </Article>
...

我希望它位于ID 333的文章节点内,这是我在函数调用中指定的。我在xpath表达式中做错了什么??或者我怎样才能做到这一点?任何帮助都将受到高度重视。祝大家新年快乐。

共有1个答案

艾文斌
2023-03-14

我在xpath表达式中做错了什么?

我可以发现的一个错误是(当用户在Stackoverflow上的PHP标签下询问xpath时很常见)您不知道脚本中可能存在的xpath注入。

因此,对于我将要给出的PHP示例,我将确保其安全性,使用的函数来自于缓解PHP中的XPath注入攻击,这也有关于该主题的更多信息。

除了这个(常见的)错误之外,直接映入眼帘的是,您在这里做了很多事情,而您可以只使用一个XPath表达式来表达它。

您希望第一个元素具有特定值的ID属性,然后包含一个子元素,该子元素至少包含三个子元素,其中三个子元素必须包含三分之一的文本。

对于333的示例ID和三个示例性文本“英语”、“法语”和“汉语”,XPath查询如下所示:

(
    //*[@ID=333]
        /*[ count(*) > 2
            and (
                *[contains(., 'English')]
                and *[contains(., 'French')]
                and *[contains(., 'Chinese')]
            )
        ]
    /..
)[1]

如您所见,围绕它包装更多的PHP代码没有多大意义。

除了这些最明显的点之外,应该注意的是,作为一个具有三个值的数组,infos比三个编号变量更好($infos=[“英语”、“法语”、“中文”];)。

例子:

$expr = sprintf("
    (
        //*[@ID=%d]
            /*[ count(*) > 2
                and (
                    *[contains(., %s)]
                    and *[contains(., %s)]
                    and *[contains(., %s)]
                )
            ]
        /..
    )[1]",
    $parentId, xpath_string($infos[0]), xpath_string($infos[1]), xpath_string($infos[2])
);

list($element) = $xml->xpath($expr) + [NULL];
if (empty($element)) {
    // element not found
    return;
}

// extend element
foreach ($record as $nodname => $val) {
    $element->addChild($nodname, $val);
}

这给出了预期的结果:

<Article ID="333">
        <author>John Silas</author>
        <pubDate>01/01/2017</pubDate>
        <Translations>
            <lang1>English</lang1>
            <lang2>French</lang2>
            <lang3>Arab</lang3>
            <lang3>Chinese</lang3>
        </Translations>
    <syntax>irrelevant</syntax><adjectives>None</adjectives><verbs>2</verbs><prepositions>5</prepositions></Article>
 类似资料:
  • 这个小小的HTML5密码字段在没有on无效属性的情况下工作得非常好(模式是:至少6个字符): 请看这里的jsFiddle。 但是,当我添加一个oninvalid属性,当用户的输入不符合模式时,该属性会发出一条自定义错误消息,整个字段将永远无效,请参见此处的代码: 请看这里的jsFiddle。 你能找出错误吗?

  • 问题内容: 这个小的HTML5密码字段可以在没有oninvalid属性的情况下完美运行(该模式说:最少6个字符): 在这里查看jsFiddle 。 但是,当我添加一个oninvalid属性,当用户的输入不适合该模式时,该属性会发出自定义错误消息,整个字段永远不会有效,请参见此处的代码: 在这里查看jsFiddle 。 你能发现错误吗? 问题答案: 如果使用设置值,则该字段无效。设置非零长度的字符串

  • 问题内容: 我一直在尝试制作一个Java项目。它使用Struts 2标签。无论何时要单击都有一个按钮,它应该更新数据库中的值。 但我收到此错误: 没有为操作com.comviva.im.ui.action.sysadmin.CUGAction和结果输入定义结果 问题答案: 没有为操作com.comviva.im.ui.action.sysadmin.CUGAction和结果输入定义结果 这意味着您

  • 我的Xpath是正确的 代码:- 这是运行测试用例的chrome窗口的截图:在这里你也可以看到元素是可见的 错误消息图像

  • 在我用Talend 6.5构建的路由中,使用了Saxon 9.5 jar,因此所有XPath谓词都使用Saxon进行评估。 升级到Talend 7.1以使用较新的Camel版本后,现在使用的是saxon 9.8版本,我从中了解到(带有saxon的Apache Camel Xpath 2.0在RouteBuilder/Predicates中似乎不起作用),9.6不会自动使用。 理想情况下,我希望Ca

  • 问题内容: 我已经做了几次尝试,以使包注释@ParametersAreNonnullByDefault在maven项目中为我工作,但没有成功。有人可以共享一个指向最小/示例maven项目的链接吗(或发布了pom.xml和package- info.java和demo类)? 我说的是让findbugs处理器为我实施它。 问题答案: 如何申请 在您的程序包中创建一个文件,以在其中强制执行所需的行为。