How to apply XML Namespaces

I am trying to parse some xml from a SOAP API. I am quite new to XML, but i can get it to work when i only have the body of the statement. I have tried applying some simple namespaces, but I am not sure whether this is the right path to pursue.

DECLARE @XmlFile XML = 
'<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <soap:Body>
        <Account_GetDataArrayResponse xmlns="http://e-conomic.com">
            <Account_GetDataArrayResult>
                <AccountData>
                    <Handle>
                        <Number>1000</Number>
                    </Handle>
                    <Number>1000</Number>
                    <Name>RESULTATOPGØRELSE</Name>
                    <Type>Heading</Type>
                    <DebitCredit>Debit</DebitCredit>
                    <IsAccessible>true</IsAccessible>
                    <BlockDirectEntries>false</BlockDirectEntries>
                    <Balance>0.00</Balance>
                </AccountData>
                <AccountData>
                    <Handle>
                        <Number>1001</Number>
                    </Handle>
                    <Number>1001</Number>
                    <Name>Omsætning</Name>
                    <Type>Heading</Type>
                    <DebitCredit>Debit</DebitCredit>
                    <IsAccessible>true</IsAccessible>
                    <BlockDirectEntries>false</BlockDirectEntries>
                    <Balance>0.00</Balance>
                </AccountData>
            </Account_GetDataArrayResult>
        </Account_GetDataArrayResponse>
    </soap:Body>
</soap:Envelope>'

;WITH XMLNAMESPACES( 'http://www.w3.org/2001/XMLSchema' AS e) 


SELECT
    AccountHandleNumber = AccountData.value('(Handle/Number)[1]', 'int')
    ,AccountName = AccountData.value('(Name)[1]', 'varchar(20)')
    ,AccountNumber = AccountData.value('(Number)[1]', 'int')
    ,AccountType = AccountData.value('(Type)[1]','varchar(20)')
    ,AccountDebitCredit = AccountData.value('(DebitCredit)[1]', 'varchar(20)')
    ,AccountIsAccessible = AccountData.value('(IsAccessible)[1]', 'varchar(20)')
    ,AccountBlockDirectEntries = AccountData.value('(BlockDirectEntries)[1]', 'varchar(20)')
    ,AccountBalance = AccountData.value('(Balance)[1]', 'float')
FROM  @XMLFile.nodes('/Account_GetDataArrayResponse/Account_GetDataArrayResult/AccountData') AS XTbl(AccountData)

Upvotes: 1

Views: 46

Answers (1)

marc_s
marc_s

Reputation: 754298

Yes, this is very much the right way!

However, you're not reading the entire XML you have - you have to really start at the root node - so try to adapt your code like this:

;WITH XMLNAMESPACES('http://schemas.xmlsoap.org/soap/envelope/' AS e, 
                    DEFAULT 'http://e-conomic.com') 
SELECT
    AccountHandleNumber = AccountData.value('(Handle/Number)[1]', 'int')
    ..... 
FROM  
    @XMLFile.nodes('/e:Envelope/e:Body/Account_GetDataArrayResponse/Account_GetDataArrayResult/AccountData') AS XTbl(AccountData)

First of all - you need to also take care of the <soap:Envelope> and <soap:Body> tags at the very beginning of the document - you've created a XML namespace alias of e for that - so you need to include /e:Envelope/e:Body at the beginning of your XPath expression in the .nodes() call.

Also: the <Account_GetDataArrayResponse> node declares another XML namespace which gets applied throughout the rest of the XML document - I've added that as the DEFAULT XML namespace to the query, so it will be applied to any node in the XPath expression that doesn't have an explicit XML namespace prefix associated with it

Upvotes: 1

Related Questions