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