XSLT:如何检查一个父节点中的某些节点是否相等

时间:2010-07-06 17:40:12

标签: xml xslt

我正在考虑一个XSL片段,它会检查一个班级是否所有学生都有相同的姓氏。是的,那么(做任何事情)打印“所有的姓氏都是相同的”否则打印“所有的姓氏都不一样”。

打印什么并不重要。我只是想为它找到合适的逻辑。

以下是我的示例XML:

<root>
    <class name="Physics">
        <student>
            <firstname>John</firstname>
            <lastname>Doe</lastname>
            <age>21</age>
        </student>
        <student>
            <firstname>Mary</firstname>
            <lastname>Doe</lastname>
            <age>21</age>
        </student>
        <student>
            <firstname>Ralph</firstname>
            <lastname>Doe</lastname>
            <age>21</age>
        </student>
    </class>
    <class name="Math">
        <student>
            <firstname>John</firstname>
            <lastname>Doe</lastname>
            <age>21</age>
        </student>
        <student>
            <firstname>Mary</firstname>
            <lastname>Doe</lastname>
            <age>21</age>
        </student>
        <student>
            <firstname>Tee</firstname>
            <lastname>Rex</lastname>
            <age>21</age>
        </student>
    </class>
</root>

因此,对于Physics类,它会打印“所有姓氏都相同”。 对于数学课,它会打印“所有姓氏都不相同”。

(这不是我真正的XML,因为它对于一个较小的问题是不可简化的,所以我自定义使用这个XML代表我的问题)

非常感谢任何帮助。

的问候, Shobhit

3 个答案:

答案 0 :(得分:4)

嗯。对此问题一无所知,我会这样做:

<xsl:template match="class">
  <xsl:choose>
    <xsl:when test="
      count(student[not(lastname = preceding-sibling::student/lastname)]) = 1
    ">
      <xsl:text>all lastnames are same</xsl:text>
    <xsl:when>
    <xsl:otherwise>
      <xsl:text>all lastnames are not same</xsl:text>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

XPath表达式

student[not(lastname = preceding-sibling::student/lastname)]

选择<student>与同一类中任何前一个姓氏不同的所有<lastname>个节点。

在具有所有相同姓氏的班级中,他们的计数正好为1(因为第一个学生总是有一个不同于前任姓氏的姓氏)。如果计数高于1,那么该班级的一些学生会有不同的姓氏。

在上述逻辑中,类完全没有学生的情况将被识别为<xsl:otherwise>个案。您可能希望以某种方式明确处理该情况。

答案 1 :(得分:2)

此样式表:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="student"/>
    <xsl:template match="student[1]">all lastnames are same</xsl:template>
    <xsl:template match="student[1][lastname != ../student/lastname]" priority="1">all lastnames are not same</xsl:template>
</xsl:stylesheet>

结果:

<root>
    <class name="Physics">all lastnames are same</class>
    <class name="Math">all lastnames are not same</class>
</root>

注意:节点集比较。

修改:抱歉,小姐@name。

编辑2 :紧凑型。注意@priority以避免错误恢复。

答案 2 :(得分:1)

这种转变:

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

 <xsl:key name="kstudentByName"
  match="student" use="lastname"/>

 <my:text>
   <text> not </text>
 </my:text>

 <xsl:variable name="vText" select="document('')/*/my:text/*"/>

 <xsl:template match="/">
  <xsl:variable name="vNumNames" select=
   "count(*/*/student[generate-id()
                     =
                      generate-id(key('kstudentByName', lastname)[1])
                     ]
         )

         > 1
   "/>

   All names are <xsl:value-of select="$vText[$vNumNames]"/> the same.
 </xsl:template>
</xsl:stylesheet>

应用于提供的XML文档时会产生正确的结果:

  All names are  not  the same.

请注意使用键,这使得此转换更有效,而不是将每个名称与所有前一个兄弟的名称进行比较的时间复杂度的二次方