简体   繁体   中英

How to parse xml tags with multiple xmlns attribute?

I have a xml value. I Am try to parse this, but result is null My Xml

<DataPDU xmlns="urn:cma:stp:xsd:stp.1.0">
    <Body>
        <AppHdr xmlns="urn:iso:std:iso:20022:tech:xsd:head.001.001.01">
            <Fr>
            <FIId>
                <FinInstnId>
                    <ClrSysMmbId>
                        <MmbId>4588745121</MmbId>
                    </ClrSysMmbId>
                </FinInstnId>
            </FIId>
        </Fr>
        <To>
            <FIId>
                <FinInstnId>
                    <ClrSysMmbId>
                        <MmbId>3501548751245701797</MmbId>
                    </ClrSysMmbId>
                </FinInstnId>
            </FIId>
        </To>
        <BizMsgIdr>Pac.Convert</BizMsgIdr>
        <MsgDefIdr>Pac.Convert.2019</MsgDefIdr>
        <BizSvc>Line</BizSvc>
        <CreDt>2019-06-07T17:06:35.38Z</CreDt>
        </AppHdr>
</Body>
</DataPDU>

My query to parse work good without attribute but with attribute returned null My query:

 Select 

    x.XmlCol.value(N'(./Fr/FIId/FinInstnId/ClrSysMmbId/MmbId)[1]','nvarchar(200)') as FR_MmbId, --Идентификация устанавливается со стороны отправителя
    x.XmlCol.value(N'(./To/FIId/FinInstnId/ClrSysMmbId/MmbId)[1]','nvarchar(200)') as TO_MmbId,
    x.XmlCol.value(N'(./BizMsgIdr)[1]','nvarchar(200)') as BizMsgIdr
    from @Xml.nodes(N'/DataPDU/Body/AppHdr') x(XmlCol)

There are two namespaces involved. Both are without a prefix, hence showing up as the default namespace . All values are living within the inner default namespace . Therefore, to keep it simple, I suggest to use a prefix for the outer. This allows you to address all inner elements without a prefix:

;WITH XMLNAMESPACES(DEFAULT 'urn:iso:std:iso:20022:tech:xsd:head.001.001.01'
                           ,'urn:cma:stp:xsd:stp.1.0' AS ns)
SELECT AppHdr.value(N'(Fr/FIId/FinInstnId/ClrSysMmbId/MmbId/text())[1]','nvarchar(200)') as FR_MmbId
      ,AppHdr.value(N'(To/FIId/FinInstnId/ClrSysMmbId/MmbId/text())[1]','nvarchar(200)') as TO_MmbId
      ,AppHdr.value(N'(BizMsgIdr/text())[1]','nvarchar(200)') as BizMsgIdr
FROM @Xml.nodes(N'/ns:DataPDU/ns:Body/AppHdr') A(AppHdr);

Furthermore, you might omit the outer namespace and use wildcard:

;WITH XMLNAMESPACES(DEFAULT 'urn:iso:std:iso:20022:tech:xsd:head.001.001.01')
SELECT AppHdr.value(N'(Fr/FIId/FinInstnId/ClrSysMmbId/MmbId/text())[1]','nvarchar(200)') as FR_MmbId
      ,AppHdr.value(N'(To/FIId/FinInstnId/ClrSysMmbId/MmbId/text())[1]','nvarchar(200)') as TO_MmbId
      ,AppHdr.value(N'(BizMsgIdr/text())[1]','nvarchar(200)') as BizMsgIdr
FROM @Xml.nodes(N'/*:DataPDU/*:Body/AppHdr') A(AppHdr);

And the deep search with a doubled slash at the beginning would work too (as long as there is only one <AppHdr> element in your XML.

;WITH XMLNAMESPACES(DEFAULT 'urn:iso:std:iso:20022:tech:xsd:head.001.001.01')
SELECT AppHdr.value(N'(Fr/FIId/FinInstnId/ClrSysMmbId/MmbId/text())[1]','nvarchar(200)') as FR_MmbId
      ,AppHdr.value(N'(To/FIId/FinInstnId/ClrSysMmbId/MmbId/text())[1]','nvarchar(200)') as TO_MmbId
      ,AppHdr.value(N'(BizMsgIdr/text())[1]','nvarchar(200)') as BizMsgIdr
FROM @Xml.nodes(N'//AppHdr') A(AppHdr);

Just for fun: This works too (with the given XML, this is not recommended ) :

SELECT @xml.value(N'(//*:Fr//*:MmbId/text())[1]','nvarchar(200)') as FR_MmbId
      ,@xml.value(N'(//*:To//*:MmbId/text())[1]','nvarchar(200)') as TO_MmbId
      ,@xml.value(N'(//*:BizMsgIdr/text())[1]','nvarchar(200)') as BizMsgIdr

And even this works (with the given XML, this is not recommended ) :-)

SELECT @xml.value(N'(//*:Fr)[1]','nvarchar(200)') as FR_MmbId
      ,@xml.value(N'(//*:To)[1]','nvarchar(200)') as TO_MmbId
      ,@xml.value(N'(//*:BizMsgIdr)[1]','nvarchar(200)') as BizMsgIdr

The general advise is: Be as specific as possible. This helps to avoid name clashes and is better in performance.

You need to handle XMLNAMESPACES (xmlns) in different nodes to get your desired output. Try as below-

;WITH XMLNAMESPACES(
            'urn:cma:stp:xsd:stp.1.0' AS N1,
            'urn:iso:std:iso:20022:tech:xsd:head.001.001.01' AS N2,
            DEFAULT 'urn:cma:stp:xsd:stp.1.0'
)

Select 
x.XmlCol.value(N'(./N2:Fr/N2:FIId/N2:FinInstnId/N2:ClrSysMmbId/N2:MmbId)[1]','nvarchar(200)') as FR_MmbId, --Идентификация устанавливается со стороны отправителя
x.XmlCol.value(N'(./N2:To/N2:FIId/N2:FinInstnId/N2:ClrSysMmbId/N2:MmbId)[1]','nvarchar(200)') as TO_MmbId,
x.XmlCol.value(N'(./N2:BizMsgIdr)[1]','nvarchar(200)') as BizMsgIdr
from @Xml.nodes(N'/N1:DataPDU/Body/N2:AppHdr') x(XmlCol)

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