当我需要考虑两个xml节点的内容时,如何在使用XPath 1.0的XML中找到不同的节点

时间:2019-06-27 06:21:58

标签: xslt-1.0 xpath-1.0

这是我的第一个问题。

我正在尝试创建一个将XML转换为Text的xslt。 我需要找到 Lang OFFICEID 串联的​​不同列表,然后可以将其用于 xsl:for-each 循环

我已经创建了一个最小的XML版本

    <docinfo>
        <printfile customer="Migrol">
            <envelope postagetype="A">
                <index name="LANG" value="G"/>
                <index name="OFFICEID" value="500"/>
            </envelope>
            <envelope postagetype="A">
                <index name="LANG" value="F"/>
                <index name="OFFICEID" value="500"/>
            </envelope>
            <envelope postagetype="A">
                <index name="LANG" value="G"/>
                <index name="OFFICEID" value="500"/>
            </envelope>
            <envelope postagetype="A">
                <index name="LANG" value="I"/>
                <index name="OFFICEID" value="300"/>
            </envelope>
            <envelope postagetype="A">
                <index name="LANG" value="G"/>
                <index name="OFFICEID" value="100"/>
            </envelope>
            <envelope postagetype="A">
                <index name="LANG" value="G"/>
                <index name="OFFICEID" value="100"/>
            </envelope>
            <envelope postagetype="A">
                <index name="LANG" value="I"/>
                <index name="OFFICEID" value="300"/>
            </envelope>
            <envelope postagetype="A">
                <index name="LANG" value="G"/>
                <index name="OFFICEID" value="500"/>
            </envelope>
        </printfile>
    </docinfo>

对于XPath 2.0,可以使用Statement来解决

/docinfo/printfile/distinct-values(envelope/concat(index[@name='OFFICEID']/@value, index[@name='LANG']/@value))

/docinfo/printfile/envelope[not(concat(index[@name='OFFICEID']/@value, index[@name='LANG']/@value)=preceding-sibling::envelope/concat(index[@name='OFFICEID']/@value, index[@name='LANG']/@value))]/concat(index[@name='OFFICEID']/@value, index[@name='LANG']/@value)

遗憾的是,我还没有找到在XPath 1.0中实现这一目标的方法。 concat函数似乎在这里给我带来麻烦。

我要使用的XSLT的简单版本

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="text"/>

    <xsl:template match="printfile">

        <xsl:for-each select="/docinfo/printfile/envelope[not(concat(index[@name='OFFICEID']/@value, index[@name='LANG']/@value)=preceding-sibling::envelope/concat(index[@name='OFFICEID']/@value, index[@name='LANG']/@value))]">
            <xsl:variable name="OID" select="index[@name='OFFICEID'][1]/@value"/>
            <xsl:variable name="LANG" select="index[@name='LANG'][1]/@value"/>

            <xsl:value-of select="$OID"/>
            <xsl:text> </xsl:text>
            <xsl:value-of select="$LANG"/>

            <xsl:text>&#10;</xsl:text>
        </xsl:for-each>

    </xsl:template>

    <!-- suppress default text -->
    <xsl:template match="text()"/>
</xsl:stylesheet>

结果应类似于

"500 G"
"500 F"
"300 I"
"100 G"

有人建议如何使用XSLT和XPath 1.0实现这一目标吗?

1 个答案:

答案 0 :(得分:0)

在XSLT 1.0中提取不同值的首选方法是使用Muenchian grouping

在您的示例中,您需要使用复合键:

XSLT 1.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>

<xsl:key name="env" match="envelope" use="concat(index[@name='OFFICEID']/@value, index[@name='LANG']/@value)" />

<xsl:template match="/docinfo">
    <xsl:for-each select="printfile/envelope[count(. | key('env', concat(index[@name='OFFICEID']/@value, index[@name='LANG']/@value))[1]) = 1]">
        <xsl:value-of select="index[@name='OFFICEID']/@value"/>
        <xsl:text> </xsl:text>
        <xsl:value-of select="index[@name='LANG']/@value"/>
        <xsl:text>&#10;</xsl:text>
    </xsl:for-each>
</xsl:template>

</xsl:stylesheet>

请注意,在大多数情况下,定义键时会包含分隔符,例如

<xsl:key name="env" match="envelope" use="concat(index[@name='OFFICEID']/@value, '|', index[@name='LANG']/@value)" />

防止误报。