简体   繁体   English

在TSQL中使用变量节点名称构造xml

[英]Construct xml with variable node names in TSQL

In my application I am running a rather complex query using FOR XML PATH() to construct an xml result. 在我的应用程序中,我正在使用FOR XML PATH()运行一个相当复杂的查询,以构造一个xml结果。 I am using this query in several stored procedures but each the root node and the first level node names are different. 我在几个存储过程中使用此查询,但是每个根节点和第一级节点名称都不相同。 What I would like to do is create a scalar user defined function that takes the two node names as parameters and returns the correct xml. 我想做的是创建一个标量用户定义函数,该函数将两个节点名称作为参数并返回正确的xml。 The expected output would look like this: 预期的输出如下所示:

<{root node name}>
    <{first level node name}  attr1="value1" attr2="value2">
        <detail attr1="value3">
            <error code="1" descr="some error"/>
            <error code="3" descr="some other error"/>
        </detail>
    </{first level node name}>
    <error code="4" descr="yet another error"/>
</{root node name}>

With {root node name} and {first level node name} being passed as parameters 通过传递{根节点名称}和{一级节点名称}作为参数

I know I can use dynamic SQL to do this but it can be very cumbersome and I would like to avoid it. 我知道我可以使用动态SQL来做到这一点,但是它可能非常麻烦,我想避免这样做。 I could also do it easily in C# or using XSLT but I need to do this entirely in SQL as it will be called from SQL Service broker handlers. 我也可以在C#或使用XSLT中轻松完成此操作,但是我需要完全在SQL中完成此操作,因为它将从SQL Service代理处理程序中调用。

Unfortunately FOR XML PATH requires a literal for the node name. 不幸的是, FOR XML PATH要求节点名称使用文字。 I also tried creating the xml with known generic node names and then trying to replace them using XQuery, but that also requires literals. 我还尝试使用已知的通用节点名称创建xml,然后尝试使用XQuery替换它们,但这也需要文字。 Both the XQuery has to be a literal and the node names used in node constructors need to be literals as well (cannot use sql:variable() ) XQuery必须是文字,并且节点构造函数中使用的节点名称也必须是文字(不能使用sql:variable()

Is there any way create XML with dynamic node names? 有什么办法可以用动态节点名创建XML?

As the elements names are built out of the result set's column names this cannot work (other than dynamic SQL or CLR), but there is rescue: 由于元素名称是从结果集的列名称中构建出来的,因此它不起作用(动态SQL或CLR除外),但是可以解决:

DECLARE @rowName NVARCHAR(10)=N'TheRow';
DECLARE @rootName NVARCHAR(10)=N'TheRoot';

DECLARE @OutputXml XML=
CAST(
    REPLACE(REPLACE(
    CAST((SELECT TOP 2 [name],[type] 
          FROM sys.objects 
          FOR XML PATH(N'ThisIsAStringOnlyUsedAsRowElementName')
                 ,ROOT(N'TheSameIdeaForTheRootName')
                 ,TYPE) AS NVARCHAR(MAX))
    ,N'ThisIsAStringOnlyUsedAsRowElementName',@rowName)
    ,N'TheSameIdeaForTheRootName',@rootName) AS XML);


SELECT @outputXML;

The result 结果

<TheRoot>
  <TheRow>
    <name>spt_fallback_db</name>
    <type>U </type>
  </TheRow>
  <TheRow>
    <name>spt_fallback_dev</name>
    <type>U </type>
  </TheRow>
</TheRoot>

In general I'd avoid string manipulations on an XML (due to possible side effects and performance impact). 通常,我会避免对XML进行字符串操作(由于可能的副作用和性能影响)。 But I think this is a legit workaround... 但是我认为这是一个合法的解决方法...

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM