XSLT按年分类和过滤

时间:2014-06-04 09:59:35

标签: xml xslt

我有以下xml:

<?xml version="1.0" encoding="UTF-8"?>
<notes>
 <note>
   <to>Aaa</to>
   <from>1985</from>
 </note>
 <note>
   <to>Bbb</to>
   <from>2009</from>
 </note>
 <note>
   <to>Ccc</to>
   <from>2010</from>
 </note>
 <note>
  <to>Aaaaaa</to>
  <from>2008</from>
 </note>
</notes>

和xsl:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:key name="initial" match="note" use="substring(to,1,1)" />

<xsl:template match="/">      
    <html>
        <body>
            <xsl:for-each select="//note[generate-id(.)= generate-id(key('initial', substring(to,1,1))[1])]">
                <xsl:for-each select="key('initial', substring(to,1,1))">      
                    <xsl:if test="from &gt;= 2000">                 
                        <xsl:if test="position() = 1">
                            <h1>Heading-<xsl:value-of select="substring(to,1,1)" /></h1>
                         </xsl:if>
                         <p><xsl:value-of select="to"/></p>
                         <p><xsl:value-of select="from"/></p>
                   </xsl:if>
                </xsl:for-each>
            </xsl:for-each>
      </body>
    </html>
</xsl:template>
</xsl:stylesheet>

这会产生:

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
</head>
<body>
 <p>Aaaaaa</p>
 <p>2008</p>
 <h1>Heading-B</h1>
    <p>Bbb</p>
     <p>2009</p>
 <h1>Heading-C</h1>
    <p>Ccc</p>
    <p>2010</p>
 </body>
 </html>

期望的输出:

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
</head>
<body>
 <h1>Heading-A</h1>
    <p>Aaaaaa</p>
    <p>2008</p>
 <h1>Heading-B</h1>
    <p>Bbb</p>
     <p>2009</p>
 <h1>Heading-C</h1>
    <p>Ccc</p>
    <p>2010</p>
 </body>
 </html>

您可以看到输出的第一部分缺少标题,即没有标题-A&#39;在打开身体标签后,我明白这是因为我的“如果&#39; xsl中日期的条件停止发生位置()= 1。不确定如何使标题工作我是否需要某种类型的分组或在循环之前按日期过滤?

如果特定字母的所有日期都在给定的2000,即没有记录的No头之前,我也不想要标题。

(请注意这是我的问题的缩减示例)。

2 个答案:

答案 0 :(得分:1)

如果你提供了更完整的测试输入,这个问题会更容易回答,例如:

<notes>
    <note>
        <to>Aa</to>
        <from>1985</from>
    </note>
    <note>
        <to>Bb</to>
        <from>2009</from>
    </note>
    <note>
        <to>Cc</to>
        <from>2010</from>
    </note>
    <note>
        <to>Aaa</to>
        <from>2008</from>
    </note>
    <note>
        <to>Dd</to>
        <from>1985</from>
    </note>
    <note>
        <to>Bbb</to>
        <from>2004</from>
    </note>
    <note>
        <to>Ddd</to>
        <from>1986</from>
    </note>
    <note>
        <to>Aaaa</to>
        <from>2005</from>
    </note>
</notes>

现在,如果要删除不包含任何早于2000的注释的标题,您可以在开头的密钥定义中执行此操作。以下样式表:

XSLT 1.0

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

<xsl:key name="note-by-initial" match="note[from &gt; 2000]" use="substring(to,1,1)" />

<xsl:template match="/">      
    <html>
    <body>
        <xsl:for-each select="notes/note[generate-id() = generate-id(key('note-by-initial', substring(to,1,1))[1])]">
            <xsl:sort select="substring(to,1,1)" data-type="text" order="ascending"/>
            <h1>Heading-<xsl:value-of select="substring(to,1,1)" /></h1>
                <xsl:for-each select="key('note-by-initial', substring(to,1,1))">
                    <xsl:sort select="from" data-type="number" order="ascending"/>
                    <p>
                        <xsl:value-of select="to" /><br/>
                        <xsl:value-of select="from" />
                    </p>
                </xsl:for-each>
        </xsl:for-each>
    </body>
    </html>
</xsl:template>

</xsl:stylesheet>

当应用于上述测试输入时,将产生:

<?xml version="1.0" encoding="UTF-8"?>
<html>
  <body>
    <h1>Heading-A</h1>
    <p>Aaaa<br/>2005</p>
    <p>Aaa<br/>2008</p>
    <h1>Heading-B</h1>
    <p>Bbb<br/>2004</p>
    <p>Bb<br/>2009</p>
    <h1>Heading-C</h1>
    <p>Cc<br/>2010</p>
  </body>
</html>

呈现为:

enter image description here

答案 1 :(得分:0)

忽略position()的测试,并将if测试作为谓词直接添加到第二个for-each中:

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

    <xsl:strip-space elements="*"/>

    <xsl:key name="initial" match="note" use="substring(to,1,1)" />

    <xsl:template match="/">      
        <html>
            <body>
                <xsl:for-each select="//note[generate-id(.)= generate-id(key('initial', substring(to,1,1))[1])]">
                    <xsl:for-each select="key('initial', substring(to,1,1))[from &gt;= 2000]">
                        <h1>Heading-<xsl:value-of select="substring(to,1,1)" /></h1>
                        <p><xsl:value-of select="to"/></p>
                        <p><xsl:value-of select="from"/></p>
                    </xsl:for-each>
                </xsl:for-each>
            </body>
        </html>
    </xsl:template>

</xsl:stylesheet>