简体   繁体   中英

parse xml as table

I have some xml like:

<MyDetails>
  <detail key="key1" value="value1" />
  <detail key="key2" value="value2" />
  <detail key="key3" value="value3" />
  <detail key="key4" value="value4" />
</MyDetails>

And I want to be able to parse it in a table format of two columns Key, and Value. How can I create a SQL function to achieve this by specifying a Node path ie in this case '/MyDetails/detail' and KeyAttributeName and ValueAttributeName. I created the following function but it gives me the error:

    ALTER FUNCTION [dbo].[GetXmlTable] (
        @XmlSource XML,
        @HierarchyPath NVARCHAR(50) = '',
        @SpecificKey NVARCHAR(255) = NULL,
        @KeyAttributeName NVARCHAR(50) = 'key',
        @ValueAttributeName NVARCHAR(50) = 'value'
        )
    RETURNS @Table TABLE (
        [Key] NVARCHAR(255),
        [Value] NVARCHAR(500)
        )
    AS
    BEGIN

        DECLARE @KeyAttribute NVARCHAR (50) = '@' + @KeyAttributeName
        DECLARE @ValueAttribute NVARCHAR (50) = '@' + @ValueAttributeName
        DECLARE @Path NVARCHAR (50) = '/' + @HierarchyPath

        INSERT INTO @Table
        SELECT XmlElement.Attribute.value(@KeyAttribute, 'nvarchar(255)') AS [Key] 
          ,XmlElement.Attribute.value(@ValueAttribute, 'nvarchar(500)') AS [Value]
        FROM @XmlSource.nodes(@Path) AS XmlElement(Attribute)
        WHERE @SpecificKey IS NULL OR XmlElement.Attribute.value(@KeyAttribute, 'nvarchar(255)') = @SpecificKey

    RETURN
END
GO

Error:

Msg 8172, Level 16, State 1, Procedure GetXmlTable, Line 12 The argument 1 of the XML data type method "nodes" must be a string literal.

Looking to call the function like this:

select * from dbo.GetXmlTable(CAST('<MyDetails>
  <detail key="key1" value="value1" />
  <detail key="key2" value="value2" />
  <detail key="key3" value="value3" />
  <detail key="key4" value="value4" />
</MyDetails>' as XML), 'MyDetails/detail', default, default, default)

UPDATE---------------

I tried using sql variable syntax but the table returned is blank. Can you please point out what I might be doing wrong:

DECLARE @KeyAttr VARCHAR(50) = N'@' + @KeyAttributeName
DECLARE @ValueAttr VARCHAR(50) = N'@' + @ValueAttributeName
DECLARE @Path VARCHAR(100) = '/' + @HierarchyPath

    INSERT INTO @Table
    SELECT XmlElement.Attribute.value('(*[local-name() = sql:variable("@KeyAttr")])[1]', 'nvarchar(255)') AS [Key]
          ,XmlElement.Attribute.value('(*[local-name() = sql:variable("@ValueAttr")][1])', 'nvarchar(500)') AS [Value]
    FROM @XmlSource.nodes('(*[local-name() = sql:variable("@Path")])') AS XmlElement(Attribute)
    WHERE @SpecificKey IS NULL OR XmlElement.Attribute.value('(*[local-name() = sql:variable("@KeyAttr")])[1]', 'nvarchar(255)') = @SpecificKey

This query will shred your XML into a simple table;

declare @xml xml = '<MyDetails>
  <detail key="key1" value="value1" />
  <detail key="key2" value="value2" />
  <detail key="key3" value="value3" />
  <detail key="key4" value="value4" />
</MyDetails>'

select 
    t.c.value('@key', 'varchar(100)') as [key],
    t.c.value('@value', 'varchar(100)') as value
from 
    @xml.nodes('/MyDetails/detail') as t(c)

The error "The argument 1 of the XML data type method "nodes" must be a string literal." means exactly what it says - you can't pass a variable as the argument to the nodes() method. You can however reference variables in the XQuery passed to Nodes() - see sql:variable() for more info.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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