XPath / XQuery kullanarak aynı XML öğesinin tüm değerlerini birleştirin


14

Ben böyle bir XML değeri var:

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

Bütün bitiştirmek istiyorum Ideğerlere ve tek bir dize olarak döndürür: ABC....

Şimdi XML'i parçalayabildiğimi, sonuçları nodeless bir XML olarak toplayabildiğimi ve .values('text()[1]', ...)sonuca uygulayabildiğimi biliyorum :

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

Ancak, tüm bunları sadece XPath / XQuery yöntemlerini kullanarak yapmak istiyorum:

SELECT @MyXml. ? ( ? );

Böyle bir yol var mı?

Bu yönde bir çözüm aramamın nedeni, gerçek XML'imin diğer öğeleri de içermesidir, örneğin:

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

Ve her biri için kullanışsız bir komut dosyası kullanmak zorunda kalmadan değerleri Itek bir dize olarak ve Jdeğerleri tek bir dize olarak ayıklamak istiyorum .

Yanıtlar:


11

Bu sizin için işe yarayabilir:

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

text()İlk Rve alttan tüm unsurları alır .

Sadece text()yapabileceğin her şeyi istiyorsan

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

Eğer değerlerini istiyorsanız Ive Jayrı yerine bunu.

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

Sonuncusu bana sohbette önerildi, ancak ilkini de son derece yararlı buluyorum. İlk yöntemi uygulayabilmem için XML verilerini farklı şekilde oluşturabilirim.
Andriy M

7

Gerçek XML yapınıza bağlı olarak, aşağıdaki gibi bir döngü kullanmayı düşünebilirsiniz:

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

bu çıktı:

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

Bu kemanı gör


1
Bu gerçekten iyi. İhtiyacım olduğunda sınırlayıcıları içerecek şekilde kolayca uyarlayabilirim. Ve hem sınırlayıcılı hem de sınırlayıcısız dizeleri tekdüze bir şekilde çıkarmak istediğim için kullanmak için çok ayrıntılı değil.
Andriy M

0

Öğeleriniz ve değerleriniz gerçekten kısa ve farklıysa, bu işe yarar:

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

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

Ancak önemsiz olmayan XML için zorlanabilir.


Öğeler kısa olabilir, ancak genel olarak değerler değildir ve öğe adlarıyla aynı karakterleri içermeyeceklerinden emin olamıyorum. Olsa da, kutu dışında yaklaşım için teşekkür ederiz.
Andriy M
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.