XSL:如何选择符合特定条件的列表中的前2个节点

时间:2013-12-20 22:11:32

标签: xslt

如果我有类似以下内容的XML(学生按分数排序)。

<?xml version="1.0" encoding="utf-8"?>
<students>
    <student>
        <name>Joe</name>
        <year>Freshman</year>
        <score>10</score>
    </student>
    <student>
        <name>Sam</name>
        <year>Senior</year>
        <score>7</score>
    </student>
    <student>
        <name>Mary</name>
        <year>Freshman</year>
        <score>4</score>
    </student>
    <student>
        <name>Ann</name>
        <year>Junior</year>
        <score>2</score>
    </student>
</students>

如何使用XSL选择不是新生的前2名学生最终得到以下内容?

从原始帖子中澄清 - 这是我在ESB上尝试做的转换的简化示例,然后再将其转发给第三方。第三方要求邮件具有不同的标签,如name1和name2。

<students>
    <name1>Sam</name1>
    <name2>Ann</name2>
</students>

我目前有以下XSL,但显然没有过滤掉新生:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" omit-xml-declaration="yes" indent="yes" />

    <xsl:template match="node()">
        <xsl:copy>
            <xsl:apply-templates />
        </xsl:copy>
    </xsl:template>

    <xsl:template match="students/student[1]">
        <xsl:element name="name1">
            <xsl:value-of select="name" />
        </xsl:element>
    </xsl:template>

    <xsl:template match="students/student[2]">
        <xsl:element name="name2">
            <xsl:value-of select="name" />
        </xsl:element>
    </xsl:template>

    <xsl:template match="students/student[position() > 2]" />
</xsl:stylesheet>

感谢。

2 个答案:

答案 0 :(得分:0)

简单的事情:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" omit-xml-declaration="yes" indent="yes" />

<xsl:template match="/students">
<xsl:copy>
    <xsl:apply-templates select="student[year != 'Freshman']"/>
</xsl:copy>
</xsl:template>

<xsl:template match="student">
    <xsl:if test="position() &lt;= 2">
        <xsl:copy-of select="name"/>
    </xsl:if>
</xsl:template>

</xsl:stylesheet>

注意:使用您的示例,这将返回:

<students>
   <name>Sam</name>
   <name>Ann</name>
</students>

恕我直言,你真的不希望每个学生都有一个独特的元素名称。


修改

  

第三方要求消息具有类似的功能   <name1><name2>。 -

嗯,恕我直言,他们会很遗憾得到他们的要求。无论如何,你可以按照Daniel Haley所示的方式去做,或者也许:

...
<xsl:template match="student">
    <xsl:if test="position() &lt;= 2">
        <xsl:element name="{concat('student', position())}">
            <xsl:copy-of select="name"/>    
        </xsl:element>
    </xsl:if>
</xsl:template>

</xsl:stylesheet>

如果您想要包含有关这两名学生的更多详细信息 - 无论是现在还是将来。

答案 1 :(得分:0)

与user3016153的回答类似,但将数字添加到name元素。

XSLT 2.0

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output indent="yes"/>
    <xsl:strip-space elements="*"/>

    <xsl:template match="students">
        <xsl:copy>
            <xsl:apply-templates select="student[not(year='Freshman')]/name"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="name">
        <xsl:element name="name{position()}">
            <xsl:value-of select="."/>
        </xsl:element>
    </xsl:template>

</xsl:stylesheet>

XML输出

<students>
   <name1>Sam</name1>
   <name2>Ann</name2>
</students>

另外,我使用not(year='Freshman')代替year != 'Freshman'。这将包括根本没有year元素的学生。如果您不希望收录这些学生,请使用!=代替not()