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ます。

回答:


11

これはあなたのために働くかもしれません:

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

text()最初Rとそれ以降のすべての要素をピックアップします。

text()できることだけが必要な場合

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

あなたがのための値が必要な場合IJは別の代わりにこれを行います。

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

最後の1つはチャットで提案されましたが、最初の1つも非常に役立ちました。最初の方法を適用できるように、XMLデータを異なる方法で生成できる場合があります。
アンドリー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
これは本当にいいです。必要に応じて、区切り文字を含めるように簡単に調整できます。そして、区切り文字のある文字列とない文字列の両方を一定の方法で抽出したいので、あまり冗長ではありません。
アンドリー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の場合は苦労するかもしれません。


要素は短くてもかまいませんが、一般的な値はそうではなく、要素名と同じ文字が含まれないかどうかはわかりません。ただし、ボックスの外側のアプローチを高く評価してください。
アンドリーM
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.