元素层次结构的SQL XML解析查询

时间:2014-05-13 03:28:19

标签: sql sql-server xml

我正在尝试编写一个SQL查询,它将接收未定义模式的XML对象(YAY!),并将其转换为ElementNameValue列的两列表。一段时间后我能够得到一个简单的查询(我不是一个SQL人员)。

DECLARE @strXml XML
SET @strXml = '<xml>
  <FirstName>TEST</FirstName>
  <LastName>PERSON</LastName>
  <DOB>1/1/2000</DOB>
  <TestObject>
    <SomeProperty>CHECKED</SomeProperty>
    <EmbeddedObject>
        <SomeOtherProperty>NOT CHECKED</SomeOtherProperty>
    </EmbeddedObject>
  </TestObject>
</xml>'

DECLARE @XmlMappings TABLE
(        
    NodeName VARCHAR(64),
    Value VARCHAR(128)
) 
INSERT INTO @XmlMappings
SELECT doc.col.value('fn:local-name(.)[1]', 'varchar(64)') AS ElementName,
       doc.col.value('.', 'varchar(128)') AS Value
FROM @strXml.nodes('/xml/*') doc(Col)
SELECT * FROM @XmlMappings

此查询可以仅使用第一级元素处理指定XML的简单条件。但是,TestObject和EmbeddedObject等元素最终会变平。我正在寻找的是获得某种类型的映射,如

ElementName                                 | Value
=====================================================
FirstName                                   | TEST
LastName                                    | PERSON
DOB                                         | 1/1/2000
TestObject.SomeProperty                     | CHECKED
TestObject.EmbeddedObject.SomeOtherProperty | NOT CHECKED

对我来说,困难的部分是层次结构。运营商。我不在乎它是否是其他分隔符。得到输出,更多的是完成输出,而且我对SQL中的XML知之甚少,无法知道要查询的内容。

请注意,我也不能使用OPENXML,因为它希望在SQL Azure上部署,目前不支持该功能。

1 个答案:

答案 0 :(得分:2)

使用CTEcross apply

;with cte as
(
    select
        convert(varchar(100), x.n.value('fn:local-name(.)','varchar(100)') ) as path,
        convert(varchar(100), x.n.value('fn:local-name(.)','varchar(100)') ) AS name,
        x.n.query('*') AS children,
        x.n.value('.','varchar(1000)') as value
    from @strxml.nodes('/xml/*') AS x(n)
    union all
    select
        convert(varchar(100), x.path + '.' + c.n.value('fn:local-name(.)','varchar(100)') ),
        convert(varchar(100), c.n.value('fn:local-name(.)','varchar(100)') ) ,
        c.n.query('*'),
        c.n.value('.','varchar(1000)')
    from cte x
        cross apply x.children.nodes('*') AS c(n)
)

select path, value from cte where datalength(children) = 5