使用XPath / XQuery连接同一XML元素的所有值


14

我有这样的XML值:

<R>
  <I>A</I>
  <I>B</I>
  <I>C</I>
  ...
</R>

我想连接所有I值并将它们作为单个字符串返回:ABC...

现在我知道我可以切碎XML,将结果聚合为无节点XML,然后应用于.values('text()[1]', ...)结果:

SELECT
  (
    SELECT
      n.n.value('text()[1]', 'varchar(50)') AS [text()]
    FROM
      @MyXml.nodes('/R/I') AS n (n)
    FOR XML
      PATH (''),
      TYPE
  ).value('text()[1]', 'varchar(50)')
;

但是,我只想使用XPath / XQuery方法来做所有事情,就像这样:

SELECT @MyXml. ? ( ? );

有这种方法吗?

我正在朝这个方向寻找解决方案的原因是因为我的实际XML也包含其他元素,例如:

<R>
  <I>A</I>
  <I>B</I>
  <I>C</I>
  ...
  <J>X</J>
  <J>Y</J>
  <J>Z</J>
  ...
</R>

而且,我希望能够将I值提取为单个字符串,并将J值提取为单个字符串,而不必为每个字符串使用笨拙的脚本。

Answers:


11

这可能对您有用:

select @MyXml.value('/R[1]', 'varchar(50)')

它从头到尾拾取所有text()元素R

如果您只想一切text()都可以

select @MyXml.value('.', 'varchar(50)')

如果要使用I和的值,J请改为执行此操作。

select @MyXml.query('/R/I/text()').value('.', 'varchar(50)'),
       @MyXml.query('/R/J/text()').value('.', 'varchar(50)')

在聊天中向我建议了最后一个,但是我发现第一个也非常有帮助。我可能能够以不同方式生成XML数据,以便可以将第一种方法应用于它。
Andriy M,

7

根据您的实际XML结构,您可以考虑使用如下循环:

DECLARE @xml XML

SELECT @xml = '<R>
  <I>A</I>
  <I>B</I>
  <I>C</I>
  <J>X</J>
  <J>Y</J>
  <J>Z</J>
</R>'

SELECT 
    Tbl.Col.query('for $i in I return $i').value('.', 'nvarchar(max)'),
    Tbl.Col.query('for $i in J return $i').value('.', 'nvarchar(max)')
FROM @xml.nodes('R') Tbl(Col);

输出以下内容:

(No column name) | (No column name) 
---------------  | --------------- 
ABC              | XYZ 

看到这个小提琴


1
真的很好 只要需要,我可以轻松地对其进行修改以包括定界符。而且使用起来也不太冗长,以防万一我想以统一的方式提取带分隔符和不带分隔符的字符串。
Andriy M,

0

如果您的元素和价值观确实简短而与众不同,则可以这样做:

declare @s varchar(99) = '<R><I>A</I><I>B</I><I>C</I></R>';

select
    @s,
    REPLACE(TRANSLATE ( @s, '<>I/R', '     '), ' ', '');

对于非平凡的XML,它可能会遇到困难。


元素可以很短,但通常的值不是,而且我不能确定它们不会包含与元素名称相同的字符。不过,请欣赏“开箱即用”的方法。
Andriy M
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.