Как создать XML из фрагментов XML - PullRequest
1 голос
/ 12 февраля 2009

Я использую SQL Server 2005 и у меня есть столбец типа данных XML, в котором фрагменты XML хранятся примерно так в одной большой таблице:

row 1 ..... <Order date='2009-02-11' customerID='4' />
row 2...... <OrderItem OrderID='6' ItemID='477' quantity='1' />

Я хотел бы создать XML с использованием T-SQL, который выглядит следующим образом:

<Orders>
  <Order data='2009-02-11' customerID='4'>
    <OrderItems>
     <OrderItem OrderID='5' ItemID='477' quantity='1'/>
    </OrderItems>
  </Order>
</Orders>

Есть предложения? Спасибо вам.

Ответы [ 4 ]

2 голосов
/ 17 февраля 2009

Это более простой метод с использованием XML DML в SQL Server 2005/2008, хотя в этом есть небольшая хитрость. Поскольку вы не можете вставить sql: variable непосредственно в XML с помощью метода .modify (insert) типа данных XML, уловка заключается в том, что вы должны преобразовывать фрагменты XML в виде символьных строк, объединять их, а затем преобразовывать обратно в XML, переместите второй фрагмент внутрь первого и удалите остатки второго. Реализация не так плоха, как кажется:

DECLARE @xmlfrag1 XML
DECLARE @xmlfrag2 XML
DECLARE @xmlfrag3 XML

SET @xmlfrag1 = '<Orders />'
SET @xmlfrag2 = '<Order date="2009-02-11" customerID="4" />'
SET @xmlfrag3 = '<OrderItem OrderID="5" ItemID="477" quantity="1"/>'

SET @xmlfrag1 = CONVERT(XML, (CONVERT(NVARCHAR(MAX), @xmlfrag1) + CONVERT(NVARCHAR(MAX), @xmlfrag2)))
SET @xmlfrag1.modify('insert /*[2] as first into /*[1]')
SET @xmlfrag1.modify('delete /*[2]')
SET @xmlfrag1.modify('insert <OrderItems /> as first into (/Orders/Order)[1]')
SET @xmlfrag1 = CONVERT(XML, (CONVERT(NVARCHAR(MAX), @xmlfrag1) + CONVERT(NVARCHAR(MAX), @xmlfrag3)))
SET @xmlfrag1.modify('insert /*[2] as first into (/Orders/Order/OrderItems)[1]')
SET @xmlfrag1.modify('delete /*[2]')

SELECT @xmlfrag1

Это вернет следующее, именно то, что вы хотели:

<Orders>
  <Order date="2009-02-11" customerID="4">
    <OrderItems>
      <OrderItem OrderID="5" ItemID="477" quantity="1" />
    </OrderItems>
  </Order>
</Orders>

Как вы получаете ваши XML-фрагменты полностью зависит от вас, но этого должно быть достаточно, чтобы вы начали.

0 голосов
/ 13 ноября 2009

- Временная таблица #t - это ваша таблица. Поле OrderId является обязательным, я полагаю, существует в вашей таблице.

create table #t (OrderId int, f xml)
insert #t values (6,'')
insert #t values (6,'')


select 
 1      as tag,
 null     as parent,
 t.OrderId          as [Order!1!!hide],
 f.value('(/Order/@date)[1]','varchar(10)')  as [Order!1!data],
 f.value('(/Order/@customerID)[1]','int')  as [Order!1!customerID],
 null           as [OrderItems!2!!hide],
 null           as [OrderItem!3!OrderID],
 null           as [OrderItem!3!ItemID],
 null           as [OrderItem!3!quantity]
from #t as [t]
where 
 f.value('(/Order/@date)[1]','varchar(10)') is not null -- if is possible change the condition using another field

union all

select distinct
 2      as tag,
 1      as parent,
 t.OrderId          as [Order!1!!hide],
 null           as [Order!1!data],
 null           as [Order!1!customerID],
 1            as [OrderItems!2!!hide],
 null           as [OrderItem!3!OrderID],
 null           as [OrderItem!3!ItemID],
 null           as [OrderItem!3!quantity]
from #t as [t]

union all

select
 3      as tag,
 2      as parent,
 t.OrderId          as [Order!1!!hide],
 null           as [Order!1!data],
 null           as [Order!1!customerID],
 1            as [OrderItems!2!!hide],
 f.value('(/OrderItem/@OrderID)[1]','int')  as [OrderItem!3!OrderID],
 f.value('(/OrderItem/@ItemID)[1]','int')  as [OrderItem!3!ItemID],
 f.value('(/OrderItem/@quantity)[1]','int')  as [OrderItem!3!quantity]
from #t as [t]
where 
 f.value('(/OrderItem/@OrderID)[1]','int') is not null-- if is possible change the condition using another field


ORDER BY 
 [Order!1!!hide],
 [OrderItems!2!!hide],
 [OrderItem!3!OrderID]

FOR XML EXPLICIT, ROOT('Orders'), TYPE
0 голосов
/ 12 февраля 2009

Самым большим препятствием для решения на чистом T-SQL является конкатенация строк. Это маленькое решение T-SQL, которое я выбрал, должно сработать и быстро работать. Вероятно, было бы неплохо заключить это в UDF.

CREATE TABLE #Order ( orderId INT PRIMARY KEY,[xmlData] NVARCHAR(512) )
GO 
CREATE TABLE #OrderLines
( orderId INT, orderLine INT,[xmlData] NVARCHAR(512),CONSTRAINT [pk_OrderLines] PRIMARY KEY CLUSTERED (orderId, orderLine) )
GO
INSERT INTO #Order
SELECT 1, '<Order date="2009-02-11" customerID="4">'

INSERT INTO #OrderLines
SELECT 1, 1, '<OrderItem OrderID="1" ItemID="477" quantity="1" />' UNION ALL 
SELECT 1, 2, '<OrderItem OrderID="1" ItemID="478" quantity="1" />'

--
-- Pivot Order lines into one string value
-- 
DECLARE @OrderLines NVARCHAR(MAX)  SET @OrderLines = ''
SELECT @OrderLines = COALESCE(@OrderLines, ' ','') + [xmlData] from #OrderLines 
WHERE orderId = 1


--
-- Join document fragments together into variable.
--
DECLARE @XMLDOC NVARCHAR(MAX)  SET @XMLDOC = ''
SELECT @XMLDOC = COALESCE(@XMLDOC, ' ','') + a.C1 
FROM
(
    SELECT '<Orders>' AS C1 UNION ALL
    SELECT [xmlData] FROM #Order WHERE orderId = 1 UNION ALL
    SELECT '<OrderItems>' UNION ALL
    SELECT @OrderLines UNION ALL
    SELECT '</OrderItems>' UNION ALL
    SELECT '</Order>' UNION ALL
    SELECT '</Orders>'
) a

SELECT @XMLDOC -- OUTPUT RESULT
0 голосов
/ 12 февраля 2009

Создайте пользовательскую функцию, которая будет вызывать XmlDocument.LoadXml (). DocumentElement (root) - это просто любой другой XmlNodeList.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...