【问题标题】:How to use XSLT to group RSS feeds如何使用 XSLT 对 RSS 提要进行分组
【发布时间】:2011-07-01 20:47:25
【问题描述】:

我有一个 XML 文件,其中包含从 Internet 上的提要中读取的数据。 XML 是标准的 RSS 2.0 文件。它看起来像(我省略了一些标签来缩短帖子):

<?xml version="1.0" encoding="ISO-8859-1"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title/>
    <item>
      <title>Blah</title>
      <category>CAT1</category>
    </item>
    <item>
      <title>Blah2</title>
      <category>CAT2</category>
    </item>
    <item>
      <title>Blah3</title>
      <category>CAT1</category>
    </item>
  </channel>
</rss>

我想要做的是使用 XSLT 创建一个 HTML 文件。我的问题是我需要按类别标签对项目进行分组。为了生成类似的东西:

<div>
  <span>CAT1</span>
  <div>
    <span>Blah</span>
    <span>Blah3</span>
  </div>
</div>
<div>
  <span>CAT2</span>
  <div>
    <span>Blah2</span>
  </div>
</div>

到目前为止,我发现了一堆 os 帖子,它们教如何使用 XSLT 通过使用属性进行分组(如 thisthisthis)。但是,我所有的适应尝试都失败了。

TIA,

鲍勃

【问题讨论】:

    标签: xml xslt rss


    【解决方案1】:

    使用 Muenchian 分组方法可以轻松解决这个问题。这个样式表:

    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
        <xsl:key name="byCategory" match="item" use="category" />
        <xsl:template match="/">
            <html><xsl:apply-templates /></html>
        </xsl:template>
        <xsl:template
            match="item[generate-id()=generate-id(key('byCategory', category)[1])]">
            <div>
                <span><xsl:apply-templates select="category" /></span>
                <xsl:apply-templates select="key('byCategory', category)" 
                    mode="out" />
            </div>
        </xsl:template>
        <xsl:template match="item"/>
        <xsl:template match="item" mode="out">
            <div><xsl:apply-templates select="title" /></div>
        </xsl:template>
    </xsl:stylesheet>
    

    应用于此输入:

    <?xml version="1.0" encoding="ISO-8859-1"?>
    <rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/"
        xmlns:content="http://purl.org/rss/1.0/modules/content/">
        <channel>
            <title />
            <item>
                <title>Blah</title>
                <category>CAT1</category>
            </item>
            <item>
                <title>Blah2</title>
                <category>CAT2</category>
            </item>
            <item>
                <title>Blah3</title>
                <category>CAT1</category>
            </item>
        </channel>
    </rss>
    

    生产:

    <html>
        <div>
            <span>CAT1</span>
            <div>Blah</div>
            <div>Blah3</div>
        </div>
        <div>
            <span>CAT2</span>
            <div>Blah2</div>
        </div>
    </html>
    

    【讨论】:

      【解决方案2】:

      这应该让你开始

      <?xml version="1.0" encoding="utf-8"?>
      <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
      
      >
          <xsl:output method="html" indent="yes" omit-xml-declaration="yes"/>
      
          <xsl:template match="@* | node()">
                  <xsl:apply-templates select="@* | node()"/>
          </xsl:template>
      
          <xsl:template match="item[not(category = preceding-sibling::item/category)]">
              <xsl:variable name="category" select="category"/>
              <div>
                  <span>
                      <xsl:value-of select="category"/>
                  </span>
                  <div>
                  <span>
                      <xsl:value-of select="title"/>
                  </span>
                  <xsl:apply-templates select="following-sibling::item[category=$category]" mode="extra"/>
                  </div>
              </div>
          </xsl:template>
      
          <xsl:template match="item" mode="extra">
              <span>
                  <xsl:value-of select="title"/>
              </span>
          </xsl:template>
      </xsl:stylesheet>
      

      【讨论】:

        【解决方案3】:

        如果您能够使用 XSLT 2.0,您应该能够使用 for-each-group 对所有内容进行分组。

        例如,使用您的示例 XML 输入,这个 XSLT 2.0 样式表:

        <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
          <xsl:output method="xml" indent="yes"/>
          <xsl:strip-space elements="*"/>
        
          <xsl:template match="node()|@*">
            <xsl:copy>
              <xsl:apply-templates select="node()|@*"/>
            </xsl:copy>
          </xsl:template>
        
          <xsl:template match="rss">
            <html>
              <xsl:apply-templates/>
            </html>
          </xsl:template>
        
          <xsl:template match="channel">
              <xsl:for-each-group select="item" group-by="category">
                <xsl:variable name="catType" select="category"/>
                <div>
                  <span>
                    <xsl:value-of select="$catType"/>
                  </span>
                  <div>
                    <xsl:apply-templates select="../item[category=$catType]/title"/>
                  </div>
                </div>
              </xsl:for-each-group>
          </xsl:template>
        
          <xsl:template match="title">
            <span>
              <xsl:apply-templates/>
            </span>
          </xsl:template>
        
          <xsl:template match="category"/>
        
          <xsl:template match="item">
            <xsl:apply-templates/>
          </xsl:template>
        
        </xsl:stylesheet>
        

        产生以下输出:

        <html>
           <div>
              <span>CAT1</span>
              <div>
                 <span>Blah</span>
                 <span>Blah3</span>
              </div>
           </div>
           <div>
              <span>CAT2</span>
              <div>
                 <span>Blah2</span>
              </div>
           </div>
        </html>
        

        【讨论】:

        • 2.0的方案更加优雅。但是,由于我们使用的是 1.0,所以我会继续使用它。谢谢。
        【解决方案4】:

        XSLT 2.0 使用xsl:for-each-group 设施:

        <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
        
            <xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
            <xsl:strip-space elements="*"/>
        
            <xsl:template match="/*/*">
                <xsl:for-each-group select="item" group-by="category">
                    <div>
                        <span>
                            <xsl:value-of select="category"/>
                        </span>
                        <div>
                            <xsl:apply-templates select="current-group()/title"/>
                        </div>
                    </div>
                </xsl:for-each-group>
            </xsl:template>
        
            <xsl:template match="title">
                <span>
                    <xsl:value-of select="."/>
                </span>
            </xsl:template>
        
        </xsl:stylesheet>
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-01-25
          • 1970-01-01
          • 2013-08-31
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多