xpath让我失望

时间:2015-01-01 09:01:36

标签: php xpath

我有一个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() 任何地方都可以在任何地方添加新节点 作为匹配存在:

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给出:

...
<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的Article节点内,其中 我在函数调用中指定。我在xpath xpression中做错了什么?或如何 我能做到吗?任何帮助都会受到高度重视。新年快乐。

1 个答案:

答案 0 :(得分:0)

  

我在xpath xpression中做错了什么?

我可以发现的一个错误是(当用户在此处询问用于xpath的PHP标记下的Stackoverflow时),您不知道脚本中可能的xpath注入。

因此,对于我将给出的PHP示例,我将使其安全,所使用的函数取自Mitigating XPath Injection Attacks in PHP,其中还有关于该主题的更多信息。

除了那个(常见的)错误之外,直接进入视图的是你在这里做了很多事情,而你可以用一个XPath表达式来表达它。

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

对于333的示例ID和三个示例文本“English”,“French”和“Chinese”,XPath查询看起来像:

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

正如您所看到的,围绕它包含更多PHP代码没有多大意义。

除了这些最明显的点之外,应该注意的是,信息作为一个数组比三个数字变量($infos = ["English", "French", "Chinese"];)更好。

示例:

$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>