Комплексные оси XPath / где (схема BizTalk EDI 856) - PullRequest
1 голос
/ 30 апреля 2019

Требуется найти значение сегмента MAN02 в HL1Loop, который имеет HL03 = 'P' и HL01 = '3' (в файле, который потенциально содержит десятки HL1Loops, но я включил только пару для целей воспроизведения вопроса.)

Я так много работал:

//*[local-name()='HLLoop1'][.//*[HL03='P'] and .//*[HL01='3']]

вернет желаемый HLLoop1 (с примерами данных ниже). У меня есть причина для получения этого конкретного элемента, слишком длинная, чтобы объяснять здесь (разбор схемы Microsoft BizTalk, представляющей документ предварительного уведомления 856 EDI). Могут быть и другие HLLoop1, в которых также есть «MAN02», и это то, что мне нужно.

Теперь я хочу вернуть только значение MAN02. Пробовал это, но это не пойдет:

//*[local-name()='HLLoop1']//MAN/MAN02[.//*[HL03='P'] and .//*[HL01='3']]

Нужно ли мне добавлять дополнительные префиксы, чтобы HL03 мог возвращаться на несколько узлов, что-то вроде этого?

//*[local-name()='HLLoop1']//MAN/MAN02[.//.//.//*[HL03='P'] and .//.//.//*[HL01='3']]

или я бы добавил в конец что-то вроде этого:

//*[local-name()='HLLoop1'][.//*[HL03='P'] and .//*[HL01='3']]//*MAN02

Это дает "дополнительные нелегальные токены", и я думаю, что, возможно, добавление большего количества скобок в нужных местах исправит это.

Я знаю, что это вопрос прояснения осей и положения "где".

Пример здесь: http://www.xpathtester.com/xpath/3005df62b369fd0fff86e7b3e492a377

Данные

<ns0:X12_00401_856 xmlns:ns0="http://schemas.microsoft.com/BizTalk/EDI/X12/2006">
    <ns0:HLLoop1>
        <ns0:HL>
            <HL01>2</HL01>
            <HL02>1</HL02>
            <HL03>O</HL03>
        </ns0:HL>
        <ns0:PRF>
            <PRF01>287775</PRF01>
        </ns0:PRF>
    </ns0:HLLoop1>
    <ns0:HLLoop1>
        <ns0:HL>
            <HL01>3</HL01>
            <HL02>2</HL02>
            <HL03>P</HL03>
        </ns0:HL>
        <ns0:MAN>
            <MAN01>CP</MAN01>
            <MAN02>465467995515</MAN02>
        </ns0:MAN>
    </ns0:HLLoop1>
</ns0:X12_00401_856>

Я буду использовать его XSLT, что-то вроде этого:

      <LineItemCarrierTrackingNum>
           <xsl:variable name="currentHL02" select="HL02" /> 
           <xsl:value-of select="concat("//*[local-name()='HLLoop1'][.//*[HL03='O'] and ..//*[HL01='", $currentHL02,"']]//*MAN02";  /> 
      </LineItemCarrierTrackingNum> 

Я надеюсь, что смогу собрать XPath как переменную, как показано выше ...

Ответы [ 3 ]

1 голос
/ 30 апреля 2019

Если вы используете XSLT (и даже если нет), вам следует избегать использования /*[local-name()='..'], который может выбирать больше, чем вы предполагали (не говоря уже о том, что он не читается).Также обратите внимание, что использование явного пути более эффективно, чем ось-потомок.

Рассмотрим следующую таблицу стилей:

XSLT 1.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ns0="http://schemas.microsoft.com/BizTalk/EDI/X12/2006"
exclude-result-prefixes="ns0">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>

<xsl:template match="/ns0:X12_00401_856">
    <result>
        <xsl:value-of select="ns0:HLLoop1[ns0:HL/HL01='3' and ns0:HL/HL03='P']/ns0:MAN/MAN02"/>
    </result>
</xsl:template>

</xsl:stylesheet>

Применительно к вашему входному примеру результат будет:

<?xml version="1.0" encoding="UTF-8"?>
<result>465467995515</result>
0 голосов
/ 30 апреля 2019

Хорошо, я думаю, что понял, но хотел бы знать, есть ли лучший подход.

//*[local-name()='HLLoop1'][//*[HL03='P'] and //*[HL01='3']]//MAN02

Это был один из вариантов, которые у меня были в исходном вопросе, но мне нужно было // MAN02 вместо // * MAN02. Есть и другой способ работы, но согласитесь с комментарием, что он слишком тупой:

//*[local-name()='HLLoop1']//MAN02[..//..//*[HL03='P'] and ..//..//*[HL01='3']]

Иногда вам нужно отдохнуть на ночь и по-новому взглянуть на проблему. Проблемы с моими предыдущими попытками:

1) MAN имел пространство имен, поэтому просто пропустил // MAN02

2) Я использовал .// вместо ..// (одна точка - это я, а две точки - родительская). Так как я нашел MAN02, мне нужно пойти к двум родителям (один из родителей забирает меня обратно в MAN, а другой родитель возвращает меня в HLLOOP1).

Теперь мне нужно попробовать переменную в XSLT и посмотреть, работает ли она оттуда.

0 голосов
/ 30 апреля 2019

Простой ответ на ваш вопрос - использовать выражение //MAN02.

ОК, это, вероятно, не тот ответ, который вам нужен; но если это так, то это потому, что вы не объяснили настоящую проблему.

Получение данных с использованием XPath из одного входного документа обычно тривиально; проблема возникает, когда вы хотите создать выражение, которое будет также работать с другими документами (то есть с документами, которые каким-то образом отличаются от исходного тестового примера). Итак, вам нужно объяснить, что такое инварианты: какие части вашего образца документа являются надежными характеристиками общего класса документов, а какие являются случайными? Если все ваши документы содержат один элемент MAN02, как в вашем примере документа, то получить элемент MAN02 очень просто.

...