使用T-SQL FOR XML PATH删除空XML节点

时间:2012-11-20 07:52:58

标签: sql-server xml tsql for-xml-path

我正在使用FOR XML PATH从SQL Server 2008R2中的表构造XML。 XML必须按如下方式构造:

<Root>
    <OuterElement>
        <NumberNode>1</NumberNode>
        <FormattedNumberNode>0001</KFormattedNumberNode>
        <InnerContainerElement>
            <InnerNodeOne>0240</InnerNodeOne>
            <InnerNodeStartDate>201201</InnerNodeStartDate>
        </InnerContainerElement>
    </OuterElement>
</Root>

根据架构文件,InnerContainerElement是可选的,而InnerNodeOne则是必需的。模式文件不是我设置的,非常复杂,相互引用而没有明确的XSD命名空间,所以我不能轻易地将它们加载到数据库中。

必须从表创建XML,使用以下查询填充该表:

SELECT
    1 AS NumberNode
    , '0001' AS [FormattedNumberNode]
    , '0240' AS [InnerNodeOne]
    , '201201' AS [InnerNodeStartDate]
INTO #temporaryXMLStore
UNION
SELECT
    2 AS NumberNode
    , '0001' AS [FormattedNumberNode]
    , NULL AS [InnerNodeOne]
    , NULL AS [InnerNodeStartDate]

我可以考虑使用FOR XML PATH构建此XML的两种方法。

1)使用'InnerContainerElement'作为XML子查询的命名结果:

SELECT
    NumberNode
    , [FormattedNumberNode]
    , (
        SELECT
            [InnerNodeOne]
            , [InnerNodeStartDate]
        FOR XML PATH(''), TYPE
    ) AS [InnerContainerElement]
FROM #temporaryXMLStore
FOR XML PATH('OuterElement'), ROOT('Root') TYPE

2)使用'InnerContainerElement'作为XML子查询的输出元素,但没有命名它:

SELECT
    NumberNode
    , [FormattedNumberNode]
    , (
        SELECT
            [InnerNodeOne]
            , [InnerNodeStartDate]
        FOR XML PATH('InnerContainerElement'), TYPE
    )
FROM #temporaryXMLStore
FOR XML PATH('OuterElement'), ROOT('Root'), TYPE

然而,它们都没有产生预期的结果:在这两种情况下,结果都是

<Root>
  <OuterElement>
    <NumberNode>1</NumberNode>
    <FormattedNumberNode>0001</FormattedNumberNode>
    <InnerContainerElement>
      <InnerNodeOne>0240</InnerNodeOne>
      <InnerNodeStartDate>201201</InnerNodeStartDate>
    </InnerContainerElement>
  </OuterElement>
  <OuterElement>
    <NumberNode>2</NumberNode>
    <FormattedNumberNode>0001</FormattedNumberNode>
    <InnerContainerElement></InnerContainerElement>
    <!-- Or, when using the second codeblock: <InnerContainerElement /> -->
  </OuterElement>
</Root>

每当InnerContainerElement为空时,它仍然显示为空元素。根据模式,这是无效的:每当元素InnerContainerElement在XML中时,也需要InnerNodeOne

如何构建我的FOR XML PATH查询,以便InnerContainerElement在空的时候被遗漏?

1 个答案:

答案 0 :(得分:4)

如果没有内容,您需要确保InnerContainerElement的行数为零。

select T.NumberNode,
       T.FormattedNumberNode,
       (
         select T.InnerNodeOne,
                T.InnerNodeStartDate
         where T.InnerNodeOne is not null or
               T.InnerNodeStartDate is not null
         for xml path('InnerContainerElement'), type
       )
from #temporaryXMLStore as T
for xml path('OuterElement'), root('Root')

或者您可以将元素InnerContainerElement指定为列别名的一部分。

select T.NumberNode,
       T.FormattedNumberNode,
       T.InnerNodeOne as 'InnerContainerElement/InnerNodeOne',
       T.InnerNodeStartDate as 'InnerContainerElement/InnerNodeStartDate'
from #temporaryXMLStore as T
for xml path('OuterElement'), root('Root')