XSLT:如何检查众多节点是否有应用于所有节点的特定值

Pet*_*ter 3 xslt grouping xpath

我有以下简化的XML源:

<?xml version="1.0" encoding="UTF-8"?>
<MVKE>
<item>
    <MANDT>025</MANDT>
    <MATNR>000000000000000551</MATNR>
    <VMSTA>2</VMSTA>
</item>
<item>
    <MANDT>025</MANDT>
    <MATNR>000000000000000551</MATNR>
    <VMSTA>2</VMSTA>
</item>
<item>
    <MANDT>025</MANDT>
    <MATNR>000000000000000551</MATNR>   
    <VMSTA>2</VMSTA>
</item>
</MVKE>
Run Code Online (Sandbox Code Playgroud)

我需要比较这些<VMSTA>值.如果它们都是"2",那么我在目标XML中的标志值应该说"true"否则为"false".

我想出了这个XSLT:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output indent="yes" method="xml" encoding="UTF-8"/>

<xsl:template match="/">
    <list>
        <xsl:apply-templates select="MVKE"/>
    </list>
</xsl:template>

<xsl:template match="MVKE">
    <flag>
        <xsl:for-each select="item">
            <xsl:choose>
                <xsl:when
                    test="(preceding-sibling::*[1]/VMSTA or self::*/VMSTA = current()/VMSTA) and (current()/VMSTA='2')">
                    <xsl:value-of select="'true'"/>
                </xsl:when>
                <xsl:otherwise>
                    <xsl:value-of select="'false'"/>
                </xsl:otherwise>
            </xsl:choose>
        </xsl:for-each>
    </flag>
</xsl:template>

</xsl:stylesheet>
Run Code Online (Sandbox Code Playgroud)

但输出总是如此

<?xml version="1.0" encoding="UTF-8"?>
<list>
<flag>truetruetrue</flag>
</list>
Run Code Online (Sandbox Code Playgroud)

因为<xsl:for-each>.我也尝试过按键,<VMSTA>但也给了我3个值<flag>.如何正确比较3并且只获得一个值<flag>?我只是想复杂化吗?

Way*_*ett 7

你不需要for-each.假设上下文节点是一个MVKE元素(如示例所示),true当所有VMSTA元素的字符串值等于2(以及false存在任何其他值时)时,以下表达式返回:

not(item/VMSTA[not(.='2')])
Run Code Online (Sandbox Code Playgroud)

这是因为隐式转换item/VMSTA[not(.='2')]为布尔值.节点集的布尔值是true且仅当它是非空的时.因此,item/VMSTA[not(.='2')]true每当它选择至少一个节点,也就是当存在一个VMSTA元件,其字符串值不是2.包装表达式not()会产生否定,这是期望的结果.

完整的例子:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:output indent="yes" method="xml" encoding="UTF-8"/>
    <xsl:template match="/">
        <list><xsl:apply-templates select="MVKE"/></list>
    </xsl:template>
    <xsl:template match="MVKE">
        <flag><xsl:value-of select="not(item/VMSTA[not(.='2')])"/></flag>
    </xsl:template>
</xsl:stylesheet>
Run Code Online (Sandbox Code Playgroud)