我需要按某种顺序设置xml标签

时间:2017-05-20 00:43:54

标签: sql-server xml tsql

我有这样的xml:

<tt>
   <cpost/>
   <cpost/>
   <gx2tov />
   <kodp/>
   <Sertif1/>
   <Sertif1/>
   <slmat/>
</tt>

但我需要将其更改为:

<tt>
   <slmat/>
   <cpost/>
   <cpost/>
   <kodp/>
   <gx2tov />
   <Sertif1/>
   <Sertif1/>
</tt>

如何使用T SQL做到这一点?

2 个答案:

答案 0 :(得分:1)

已经有一个已接受的答案,但它只适用于空节点。在这种情况下,您可以根据需要输入XML ...

更多方法:

我添加了一些id属性来区分相同的元素

DECLARE @xml XML=
'<tt>
   <cpost id="1"/>
   <cpost id="2"/>
   <gx2tov/>
   <kodp/>
   <Sertif1 id="1"/>
   <Sertif1 id="2"/>
   <slmat/>
</tt>';

<slmat>放在顶部

您可以使用.query()获取完整节点,您可以在AS [node()]中使用SELECT ... FOR XML PATH()。此查询会将<slmat>放在顶部,并将所有名称放在后面(原始订单):

SELECT @xml.query(N'/tt/slmat') AS [node()]
      ,@xml.query(N'/tt/*[local-name()!="slmat"]') AS [node()]      
FOR XML PATH(N'tt');

与上述相同,但是只有一个XQuery

SELECT @xml.query
('
    <tt>
    {tt/slmat}
    {tt/*[local-name()!="slmat"]}
    </tt>
');

明确设置所有节点的特定顺序

如果您想为元素设置特定订单,可以明确地放置它们(现在我使用.nodes(),但您也可以不用 - 如上所述):

SELECT tt.query(N'slmat') AS [node()]
      ,tt.query(N'cpost') AS [node()] 
      ,tt.query(N'kodp') AS [node()] 
      ,tt.query(N'gx2tov') AS [node()] 
      ,tt.query(N'Sertif1') AS [node()] 
FROM @xml.nodes(N'/tt') AS A(tt)
FOR XML PATH(N'tt');

作为XQuery(现在有一个变量,但你可以直接使用root - 如上所述)

SELECT @xml.query
('
    let $t:=/tt
    return
    <tt>
    {$t/slmat}
    {$t/cpost}
    {$t/kodp}
    {$t/gx2tov}
    {$t/Sertif1}
    </tt>
');

所有结果都相同......

答案 1 :(得分:0)

您可以删除和插入节点:

DECLARE @xml XML = N'<tt>
   <cpost/>
   <cpost/>
   <gx2tov />
   <kodp/>
   <Sertif1/>
   <Sertif1/>
   <slmat/>
</tt>'

SET @xml.modify('delete tt/slmat[1]')
SET @xml.modify('insert <slmat /> as first into tt[1]')

SELECT @xml

或者,您可以重新排序所有节点:

DECLARE @xml XML = N'<tt>
   <cpost/>
   <cpost/>
   <gx2tov />
   <kodp/>
   <Sertif1/>
   <Sertif1/>
   <slmat/>
</tt>'

SELECT
    CONVERT(xml, '<' +t.value('local-name(.)','nvarchar(max)') + ' />')
FROM @xml.nodes('*/*') AS t(t)
ORDER BY t.value('local-name(.)','nvarchar(max)')
FOR XML PATH(''), TYPE, ROOT('tt')