Parsing OpenXML with multiple elements of the same name based on substring of content

时间:2017-08-04 12:46:04

标签: sql sql-server sql-server-2008 openxml

I am parsing an XML with multiple elements of the same name. I want to get the content of the element that starts with "M".

I found a very "dirty" way to do that but I am not happy with that. It's a combination of reading N elements with the same name and then using a CASE WHEN statement to find the correct element. It's not very nice especially because it is limited to a fixed amount of elements.

Is there a better / more generic way to do this?

FYI: I am already in discussion with the developer who is responsible for this XML structure. They will add this prefix as an attribute to the element. But until then I need a workaround.

Below is the code that you can use for testing. It will return 3 rows: M111111, M222222, NULL. The third row is NULL because the "M%" element is at the 9th position but I only read 7 elements. That's why I'm looking for a more generic approach.

declare @xmls table (
    ID int,
    xmlData xml
)

declare @i int = 0
declare @xml xml
declare @idoc int

insert into @xmls values 
(1,
'<xmlMessage>
    <Elements>
    <OtherStuffThatIsNotRelevantForThisQuestion />
        <Element>A123456</Element>
        <Element>B234567</Element>
        <Element>M111111</Element>
        <Element>C345678</Element>
        <Element>DD456789</Element>
        <Element>EEE567890</Element>
        <Element>F678901</Element>
        <Element>G789012</Element>
        <Element>H890123</Element>
    </Elements>
    <MoreStuffThatIsNotRelevantForThisQuestion />
</xmlMessage>'),
(2,
'<xmlMessage>
    <Elements>
    <OtherStuffThatIsNotRelevantForThisQuestion />
        <Element>A123456</Element>
        <Element>B234567</Element>
        <Element>C345678</Element>
        <Element>DD456789</Element>
        <Element>EEE567890</Element>
        <Element>M222222</Element>
        <Element>F678901</Element>
        <Element>G789012</Element>
        <Element>H890123</Element>
    </Elements>
    <MoreStuffThatIsNotRelevantForThisQuestion />
</xmlMessage>'),
(3,
'<xmlMessage>
    <OtherStuffThatIsNotRelevantForThisQuestion />
    <Elements>
        <Element>A123456</Element>
        <Element>B234567</Element>
        <Element>C345678</Element>
        <Element>DD456789</Element>
        <Element>EEE567890</Element>
        <Element>F678901</Element>
        <Element>G789012</Element>
        <Element>H890123</Element>
        <Element>M333333</Element>
    </Elements>
    <MoreStuffThatIsNotRelevantForThisQuestion />
</xmlMessage>')

while @i < (SELECT COUNT(*) from @xmls)
begin
    set @i = @i +1
    select @xml = xmlData from @xmls where ID = @i

    EXEC sp_xml_preparedocument @idoc OUTPUT, @xml

    SELECT
        CASE
            WHEN ElementNumber1 LIKE 'M%' and ISNUMERIC(SUBSTRING(ElementNumber1,2,6)) = 1 THEN ElementNumber1
            WHEN ElementNumber2 LIKE 'M%' and ISNUMERIC(SUBSTRING(ElementNumber2,2,6)) = 1 THEN ElementNumber2
            WHEN ElementNumber3 LIKE 'M%' and ISNUMERIC(SUBSTRING(ElementNumber3,2,6)) = 1 THEN ElementNumber3
            WHEN ElementNumber4 LIKE 'M%' and ISNUMERIC(SUBSTRING(ElementNumber4,2,6)) = 1 THEN ElementNumber4
            WHEN ElementNumber5 LIKE 'M%' and ISNUMERIC(SUBSTRING(ElementNumber5,2,6)) = 1 THEN ElementNumber5
            WHEN ElementNumber6 LIKE 'M%' and ISNUMERIC(SUBSTRING(ElementNumber6,2,6)) = 1 THEN ElementNumber6
            WHEN ElementNumber7 LIKE 'M%' and ISNUMERIC(SUBSTRING(ElementNumber7,2,6)) = 1 THEN ElementNumber7
            END
    FROM OPENXML(@idoc, 'xmlMessage')
    WITH (
        ElementNumber1 nvarchar(64) 'Elements/Element[1]',
        ElementNumber2 nvarchar(64) 'Elements/Element[2]',
        ElementNumber3 nvarchar(64) 'Elements/Element[3]',
        ElementNumber4 nvarchar(64) 'Elements/Element[4]',
        ElementNumber5 nvarchar(64) 'Elements/Element[5]',
        ElementNumber6 nvarchar(64) 'Elements/Element[6]',
        ElementNumber7 nvarchar(64) 'Elements/Element[7]'
    )

    EXEC sp_xml_removedocument @idoc
end

0 个答案:

没有答案