list XPath 1.0 查找元素的值是否在值列表中

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3025885/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-11 01:31:00  来源:igfitidea点击:

XPath 1.0 to find if an element's value is in a list of values

listxpathexpression

提问by user364902

Is there a way to construct an XPath that evaluates whether an element's value is in a predefined list of values? Something akin to this:

有没有办法构造一个 XPath 来评估元素的值是否在预定义的值列表中?类似于这样的东西:

/Location/Addr[State='TX or AL or MA']

Which would match nodes whith State elements for Texas, Alabama, or Massachusetts? I know that I can unpack the expression:

哪个将匹配带有德克萨斯州、阿拉巴马州或马萨诸塞州元素的节点?我知道我可以解压表达式:

/Location/Addr[State='TX] or  /Location/Addr[State='AL'], etc...

But this is a bit cumbersome since the xpaths are quite long, as is the list of values. My google-fu isn't turning up much on the issue...

但这有点麻烦,因为 xpath 很长,值列表也是如此。我的 google-fu 在这个问题上并没有出现太多...

回答by John Kugelman

You can check multiple conditions inside the same square brackets:

您可以在同一个方括号内检查多个条件:

/Location/Addr[State='TX' or State='AL' or State='MA']

Or if you have a really long list, you can create a list of states and use the contains()function.

或者,如果您有一个很长的列表,您可以创建一个状态列表并使用该contains()函数。

/Location/Addr[contains('TX AL MA', State)]

This will work fine for two-letter state abbreviations. If you want to make it more robust for longer strings you could add some spaces on the ends and check for _TX_, _AL_, etc. (where the underscores are spaces).

这适用于两个字母的州缩写。如果你想让它长字符串更强大的,你可以在两端添加一些空间和检查_TX__AL_等等(其中下划线是空格)。

/Location/Addr[contains(' TX AL MA ', concat(' ', State, ' '))]

回答by Stefan Steiger

Just necromancing, since XPath 2.0 has come along.

只是死灵,因为 XPath 2.0 出现了。

With XPath 2.0, you can do:

使用 XPath 2.0,您可以:

/Location/Addr[State=('TX', 'AL', 'MA')]

Alternatively, with XPath 1.0, you can use contains in combination with string-length:

或者,在 XPath 1.0 中,您可以将 contains 与 string-length 结合使用:

DECLARE @tXML xml = '<svg>
<g>
<path></path>
<path data-objid="0000X1">tt</path>
<path data-objid="0000X2"></path>
<path data-objid="0000X3"></path>
</g>
</svg>';

-- SELECT @tXML;

SELECT 
    c.p.value('(@data-objid)[1]', 'varchar(50)') AS objID 
FROM @tXML.nodes('//node()[contains("0000X1,0000X2", @data-objid) and string-length(@data-objid) != 0]') AS c(p)


SET @tXML.modify('delete //node()[contains("0000X1,0000X2", @data-objid) and string-length(@data-objid) != 0]'); 

SELECT @tXML AS del;

DECLARE @newRecord xml = '<path data-objid="0000X4"></path>'; 


-- SET @tXML.modify('insert sql:variable("@newRecord") as first into (/svg/g)[1]')
SET @tXML.modify('insert sql:variable("@newRecord") as last into (/svg/g)[1]')

SELECT @tXML AS ins;

See also: add block into specific position

另请参阅:将块添加到特定位置

And to update (with xml, you can only update one value at a time, and the text()selector finds nothing for an empty element, so you first need to empty the element, then insert the value, and that for each match):

并且要更新(使用 xml,您一次只能更新一个值,而 text()selector 找不到空元素的任何内容,因此您首先需要清空该元素,然后插入该值,以及每个匹配项的值) :

SET @tXML.modify('replace value of (//path[contains("0000X1,0000X2", @data-objid) and string-length(@data-objid) != 0]/text())[1] with "40"')
SET @tXML.modify('replace value of (//path[contains("0000X1,0000X2", @data-objid) and string-length(@data-objid) != 0]/text())[2] with "40"')

SET @tXML.modify('replace value of (//path[contains("0000X1,0000X2", @data-objid) and string-length(@data-objid) != 0]/text())[1] with ""')
SET @tXML.modify('insert text{"This Works"} into (//path[contains("0000X1,0000X2", @data-objid) and string-length(@data-objid) != 0])[1]')

SET @tXML.modify('replace value of (//path[contains("0000X1,0000X2", @data-objid) and string-length(@data-objid) != 0]/text())[2] with ""')
SET @tXML.modify('insert text{"This Works"} into (//path[contains("0000X1,0000X2", @data-objid) and string-length(@data-objid) != 0])[2]')

And to insert and delete an attribute

并插入和删除属性

-- insert attribute
-- SET @tXML.modify('insert attribute data-objid1 {"1"} into (//path[contains("0000X1,0000X2", @data-objid) and string-length(@data-objid) != 0])[1]')
-- delete attribute
-- and then, delete suddenly can remove several nodes - unlike insert or modify ... 
-- SET @tXML.modify('delete (//path[contains("0000X1,0000X2", @data-objid) and string-length(@data-objid) != 0])/@data-objid[1]')

-- only insert if there is no attribute "data-objid", therefore check with [not(@data-objid)]
-- (on replace, it doesn't create an attribute if it doesn't exist)
SET @tXML.modify('insert attribute data-objid {"1"} into (//path[not(@data-objid) and contains("0000X1,0000X2", @data-objid) and string-length(@data-objid) != 0])[1]')
SET @tXML.modify('replace value of (//path[contains("0000X1,0000X2", @data-objid) and string-length(@data-objid) != 0]/@data-objid)[1] with "Test"')

And with variables:

并带有变量:

DECLARE @testvar varchar(30); 
SET @testvar = 'abc'; 
SET @tXML.modify('insert attribute data-objid {sql:variable("@testvar")} into (//path[not(@data-objid)] and contains("0000X1,0000X2", @data-objid) and string-length(@data-objid) != 0)[1]')
SET @tXML.modify('replace value of (//path[contains("0000X1,0000X2", @data-objid) and string-length(@data-objid) != 0]/@data-objid)[1] with sql:variable("@testvar")')
SET @testvar = '0000X1,0000X2'; 
SET @tXML.modify('delete (//path[contains(sql:variable("@testvar"), @data-objid) and string-length(@data-objid) != 0])/@data-objid[1]')

Note that you should concat the attribute data-objidto ("," + objid + ","), so that modify doesn't accidentally find it if the testvar is ',0000X1a,0000X2b,'instead of ',0000X1,0000X2,'(for example)

请注意,您应该将属性连接data-objid("," + objid + ","),以便如果 testvar 是',0000X1a,0000X2b,'而不是',0000X1,0000X2,'(例如),则修改不会意外找到它

DECLARE @testvar varchar(30); 
SET @testvar = ',0000X1a,0000X2b,'; 
SET @tXML.modify('delete (//path[contains(sql:variable("@testvar"), concat(",", @data-objid, ",")) and string-length(@data-objid) != 0])/@data-objid[1]')

SELECT @tXML