6

我正在尝试编写可以从“搜索”节点读取信息并使用它执行搜索的 Xpath 语句 (1.0)。

我取得了一些不错的进展,但偶然发现了一个问题,即如果属性(用于搜索中的值)为空或不存在,则会失败。

编辑代码以简化示例:

所以这是我的示例 XML:

<xml>
    <files>
        <file name="foo" description="" rating="4"/>
        <file name="food" description="" rating="4"/>
        <file name="foobar" description="" rating="3"/>
        <file name="bar" description="" rating="3"/>
        <file name="barter" description="" rating="3"/>
        <file name="barterer" description="" rating="2"/>
    </files>
    <searches>
        <search id="1">
            <exclude>
                <file term="foo"/>
            </exclude>
        </search>
    </searches>
</xml>

和工作 XPATH:

//files/file[
            not(contains(@name, //search[@id='1']/exclude/file/@term))
]

它按预期工作......

但是,如果预期的属性丢失或为空,它将无法工作。我认为因为: contains(@attrib, "") 出于某种原因匹配所有内容,因此如果属性为 "" 或不存在,则 not() 将始终不匹配任何内容。

例如,如果我将 XML 的排除片段更改为此它会失败:

            <exclude>
                <file term=""/>
            </exclude>

也有这个:

            <exclude></exclude>

有没有办法检查空值而不执行选择?或者是否有更好的方式来构建逻辑。请记住,我不能在 Xpath2.0 中使用 Conditionals 或其他函数。

4

3 回答 3

2

如果 Xpath 函数 contains() 搜索参数为空或缺失,为什么它会返回所有内容?

因为这就是 XPath 规范所说的contains()函数应该做的事情:

如果 $arg2 的值是零长度字符串,则函数返回 true。

您可以调整您的 XPath 并使用以下内容简化一些条件:

//files/file[
            (  
                (
                    not(//search[@id='1']/include/file/@term)
                    or
                    (
                    contains(@name, //search[@id='1']/include/file/@term) 
                    or
                    contains(@description, //search[@id='1']/include/file/@term) 
                    ) 
                )
                or
                contains(@rating, //search[@id='1']/include/file/@rating)   
            )    
            and 
            ( 
                 (
                    not(//search[@id='1']/exclude/file/@term)
                    or
                    (
                    not(contains(@name, //search[@id='1']/exclude/file/@term)) 
                    and
                    not(contains(@description, //search[@id='1']/exclude/file/@term))
                    )
                )
                and
                (
                    not(//search[@id='1']/exclude/file/@rating)
                    or
                    not(contains(@rating, //search[@id='1']/exclude/file/@rating))
                )
            )

            ]
于 2012-09-02T16:43:35.610 回答
0

也许你想说类似

//files/file[
   not(contains(@name, 
                //search[@id='1']
                /exclude/file/@term))
   or not(
     normalize-string(//search[@id='1']
                      /exclude/file/@term)
   )
]
于 2012-09-13T02:11:11.770 回答
0

所以我在另一篇文章中偶然发现了答案。下面是它工作的一个例子。谢谢大家的建议。

//files/file[
    not(
        contains(
            @name,
            concat( //search[@id='1']/exclude/file/@term,
                substring('??', 1 + 2*
                    boolean( substring( //search[@id='1']/exclude/file/@term, 1 ) )
                )
            )
        )
    )
]

我放置“??”的位置 可能想用无效的字符或其他东西替换。对于使用的每个附加字符,1+ 需要增加。对我来说,我正在检查文件名,所以问号似乎是个好主意。老实说,我可能不会使用这条路线,毕竟我只是渴望解决这个问题。

这是我得到这个想法的地方: 如果 XPATH 中不存在节点,如何返回常量?

于 2013-10-24T16:43:57.467 回答