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.