如何解析具有多个xmlns属性的xml标签?

时间:2019-06-12 05:16:37

标签: sql sql-server xml

我有一个xml值。我试图解析它,但是结果为空 我的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>

我的查询解析工作很好,没有属性,但属性返回null 我的查询:

 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)

2 个答案:

答案 0 :(得分:2)

涉及两个名称空间。两者都没有前缀,因此显示为默认名称空间。所有值都位于内部默认名称空间中。因此,为简单起见,我建议对外部使用前缀。这使您可以处理所有不带前缀的内部元素:

;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);

此外,您可以省略外部名称空间并使用通配符:

;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);

在开头加上双斜杠的深度搜索也可以工作(只要XML中只有一个<AppHdr>元素即可。

;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);

只是为了好玩:这也可行(对于给定的XML,不推荐):

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

即使这样也可以(对于给定的XML,不推荐):-)

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

一般建议是:尽可能具体。这有助于避免名称冲突,并具有更好的性能。

答案 1 :(得分:1)

您需要在不同节点中处理XMLNAMESPACES(xmlns),以获得所需的输出。尝试如下-

;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)