web-dev-qa-db-fra.com

Concaténer toutes les valeurs du même élément XML à l'aide de XPath / XQuery

J'ai une valeur XML comme celle-ci:

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

Je veux concaténer toutes les valeurs de I et les renvoyer en une seule chaîne: ABC....

Maintenant, je sais que je peux déchiqueter le XML, agréger les résultats en tant que XML sans nœud et appliquer .values('text()[1]', ...) au résultat:

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)')
;

Cependant, je voudrais faire tout cela en utilisant uniquement des méthodes XPath/XQuery, quelque chose comme ceci:

SELECT @MyXml. ? ( ? );

Existe-t-il un tel moyen?

La raison pour laquelle je cherche une solution dans ce sens est que mon XML actuel contient également d'autres éléments, par exemple:

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

Et j'aimerais pouvoir extraire à la fois les valeurs I sous forme de chaîne unique et les valeurs J sous forme de chaîne unique sans avoir à utiliser un script lourd pour chacune.

14
Andriy M

Cela pourrait fonctionner pour vous:

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

Il récupère tous les éléments text() des premiers R et ci-dessous.

Si vous voulez juste tout text() vous pouvez faire

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

Si vous voulez que les valeurs de I et J se séparent, faites-le à la place.

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

En fonction de votre structure XML réelle, vous pouvez envisager d'utiliser une boucle comme celle-ci:

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);

qui produit ceci:

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

Voir ceci violon

Si vos éléments et valeurs sont vraiment courts et distincts, cela fonctionne:

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

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

Pour le XML non trivial, il peut cependant être difficile.

0
Michael Green