Как разобрать теги XML с несколькими атрибутами XML - PullRequest
1 голос
/ 12 июня 2019

У меня есть значение 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>

Мой запрос на анализ работает нормально, без атрибута, но с атрибутом, возвращенным нулем. Мой запрос:

 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 ]

2 голосов
/ 12 июня 2019

Здесь задействованы два пространства имен.Оба без префикса, поэтому отображаются как пространство имен по умолчанию .Все значения находятся во внутреннем пространстве имен по умолчанию .Поэтому для простоты предлагаю использовать префикс для внешнего.Это позволяет вам обращаться ко всем внутренним элементам без префикса:

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

И глубокий поиск 1012 * с двойной косой чертой в начале тоже будет работать (при условии, что в вашем 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 голос
/ 12 июня 2019

Вам нужно обрабатывать 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)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...