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