复杂的XPath轴/位置(BizTalk EDI 856架构)

时间:2019-04-29 21:08:24

标签: xpath xslt-1.0

要求是在具有HL03 ='P'和HL01 ='3'的HL1Loop中查找MAN02段的值(在一个可能包含数十个HL1Loops的文件中,但出于此目的,我仅包括其中的几个复制问题。)

我的工作量很大:

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

将返回所需的HLLoop1(以下示例数据)。我有理由要获得该特定项目,在这里过长而无法解释(解析表示856 EDI提前发货通知文档的Microsoft BizTalk模式)。可能还有其他的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

这提供了“额外的非法令牌”,我认为也许在正确的位置添加更多的括号可以解决该问题。

我知道这是使轴和“ where子句”变直的问题。

此处的示例: 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 个答案:

答案 0 :(得分:1)

如果您正在使用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>

答案 1 :(得分:0)

您问题的简单答案是使用表达式//MAN02

好的,那可能不是你想要的答案;但是如果是这样,那是因为您还没有解释真正的问题。

使用XPath从单个输入文档获取数据通常很简单;当您要构造一个也可以与其他文档一起使用的表达式时(即,与初始测试用例有某种不同的文档),就会出现问题。因此,您需要解释不变性是什么:样本文档的哪些部分是一般文档类别的可靠特征,哪些部分是偶然的?如果您的所有文档都包含与示例文档相同的单个MAN02元素,则检索MAN02元素非常简单。

答案 2 :(得分:0)

好的,我想我明白了,但是我想知道是否有更好的方法。

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

这是我最初的问题中的选项之一,但需要// MAN02而不是// * MAN02。也有另一种工作方式,但是同意它太钝的评论:

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

有时,您必须休息一晚,并对问题有新的认识。 我以前尝试的问题:

1)MAN有一个名称空间,因此跳过// MAN02

2)我使用的是.//而不是..//(一个点是self,两个点是parent)。 因为找到了MAN02,所以我必须抚养两个父母(一个父母将mae带回MAN,另一个父母将我带回到HLLOOP1)。

现在,我需要尝试XSLT中的变量,看看它是否可以从那里工作。