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
XPath 1.0 to find if an element's value is in a list of values
提问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-objid
to ("," + 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