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

How do I find distinct nodes in an XML with XPath 1.0 when I need to take the content of two xml nodes into account

这是我的第一个问题。

我正在尝试创建一个将 XML 转换为文本的 xslt。 我需要找到 LANGOFFICEID 连接的不同列表,然后可以在 xsl:for-每个 循环

我已经创建了我正在使用的 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,这可以通过使用语句

来解决
/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 实现这一目标提出建议

在 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)" />

防止误报。