Checking all values in the element are same

2020-03-01 19:41发布

问题:

I have an xml like, values can be

<n1>value1</n1>
<n1>value1</n1>
<n1>value2</n1>

I need to check if all these values are same and if same I would need to assign it to another element. I am using XSLT v1.0.

Thanks,

回答1:

Good question, +1.

Just use:

not(/*/n1[1] != /*/n1)

Assuming that all n1 elements are selected in a variable named $v, this can be expressed in just 14 characters-long XPath expression:

not($v[1] != $v)

Explanation 1:

By definition:

/*/n1[1] != /*/n1

is true() exactly if there exists a node in /*/n1 whose string value isn't equal to the string value of /*/n1[1]

The logical negation of this:

not(/*/n1[1] != /*/n1)

is true() iff no node in /*/n1 exists whose string value isn't equal to the string value of /*/n1[1] -- that is, if all nodes in /*/n1 have the same sting value.

Explanation 2:

This follows from a more general double negation law :

every x has property y

is equivalent to:

There is no x that doesn't have property y


回答2:

Assume a document of this form:

<root>
    <n1>value1</n1>
    <n1>value1</n1>
    <n1>value1</n1>
</root>

The following simple stylesheet determines whether every n1 element has the same value:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="text" omit-xml-declaration="yes"/>
    <xsl:template match="/">
        <xsl:value-of select="
            concat('All same? ', count(/*/n1[.=/*/n1[1]])=count(/*/n1))"/>
    </xsl:template>
</xsl:stylesheet>

Output:

All same? true

The key to this stylesheet is the expression:

count(/*/n1[.=/*/n1[1]])=count(/*/n1))

...which compares the count of the n1 elements whose value equals the value of the first n1 element to the count of all n1 elements. These counts will be equal only when every n1 node has the same value.

This can be made a little easier to read by first selecting all n1 into a variable named n:

count($n[.=$n[1]])=count($n)

Conditionally perform some action based on the result like this:

<xsl:template match="/">
    <xsl:variable name="all" select="count(/*/n1[.=/*/n1[1]])=count(/*/n1)"/>
    <xsl:if test="$all">All same</xsl:if>
    <xsl:if test="not($all)">Not all same</xsl:if>
</xsl:template>


标签: xslt