XSL效率问题 - 需要解决方案

时间:2009-12-23 12:45:53

标签: xslt performance

我有一个有趣的XSL场景由你们运行。到目前为止,我的解决方案似乎效率低下(转换时间显着增加),所以我想把它放在那里。

方案 从以下XML中我们需要获取每个类别的最新新闻的ID。

XML 在XML中,我有一个新闻项列表,一个新闻类别列表和一个项目类别关系列表。项目列表和项目类别列表也可以是随机顺序(不是按日期排序)。

<news>

    <itemlist>
        <item id="1">
            <attribute name="title">Great new products</attribute>
            <attribute name="startdate">2009-06-13T00:00:00</attribute>
        </item>
        <item id="2">
            <attribute name="title">FTSE down</attribute>
            <attribute name="startdate">2009-10-01T00:00:00</attribute>
        </item>
        <item id="3">
            <attribute name="title">SAAB go under</attribute>
            <attribute name="startdate">2008-01-22T00:00:00</attribute>
        </item>
        <item id="4">
            <attribute name="title">M&amp;A on increase</attribute>
            <attribute name="startdate">2010-05-11T00:00:00</attribute>
        </item>
    </itemlist>

    <categorylist>
        <category id="1">
            <name>Finance</name>
        </category>
        <category id="2">
            <name>Environment</name>
        </category>
        <category id="3">
            <name>Health</name>
        </category>
    </categorylist>

    <itemcategorylist>
        <itemcategory itemid="1" categoryid="2" />
        <itemcategory itemid="2" categoryid="3" />
        <itemcategory itemid="3" categoryid="1" />
        <itemcategory itemid="4" categoryid="1" />
        <itemcategory itemid="4" categoryid="2" />
        <itemcategory itemid="2" categoryid="2" />
    </itemcategorylist>

</news>

我尝试了什么 使用rtf

<xsl:template match="/">

        <!-- for each category -->
        <xsl:for-each select="/news/categorylist/category">

            <xsl:variable name="categoryid" select="@id"/>

            <!-- create RTF item list containing only items in that list ordered by startdate -->
            <xsl:variable name="ordereditemlist">
                <xsl:for-each select="/news/itemlist/item">
                    <xsl:sort select="attribute[@name='startdate']" order="descending" data-type="text"/>
                    <xsl:variable name="itemid" select="@id" />
                    <xsl:if test="/news/itemcategorylist/itemcategory[@categoryid = $categoryid][@itemid=$itemid]">
                        <xsl:copy-of select="."/>
                    </xsl:if>
                </xsl:for-each>
            </xsl:variable>

            <!-- get the id of the first item in the list -->
            <xsl:variable name="firstitemid" select="msxsl:node-set($ordereditemlist)/item[position()=1]/@id"/>

        </xsl:for-each>

    </xsl:template>

非常感谢您的任何想法。

谢谢, 亚历

3 个答案:

答案 0 :(得分:5)

我将如何做到这一点:

<xsl:stylesheet 
  version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>
  <xsl:output encoding="utf-8" />

  <!-- this is (literally) the key to the solution -->    
  <xsl:key name="kItemByItemCategory" match="item" use="
    /news/itemcategorylist/itemcategory[@itemid = current()/@id]/@categoryid
  " />

  <xsl:template match="/news">
    <latest>
      <xsl:apply-templates select="categorylist/category" mode="latest" />
    </latest>
  </xsl:template>

  <xsl:template match="category" mode="latest">
    <xsl:variable name="self" select="." />
    <!-- sorted loop to get the latest news item -->
    <xsl:for-each select="key('kItemByItemCategory', @id)">
      <xsl:sort select="attribute[@name='startdate']" order="descending" />
      <xsl:if test="position() = 1">
        <category name="{$self/name}">
          <xsl:apply-templates select="." />
        </category>
      </xsl:if>
    </xsl:for-each>
  </xsl:template>

  <xsl:template match="item">
    <!-- for the sake of the example, just copy the node -->
    <xsl:copy-of select="." />
  </xsl:template>

</xsl:stylesheet>

<xsl:key>按关联的类别ID为每个新闻项编制索引。现在,您可以通过一种简单的方法检索属于某个类别的所有新闻项。剩下的就是直截了当。

为我输出:

<latest>
  <category name="Finance">
    <item id="4">
      <attribute name="title">M&amp;A on increase</attribute>
      <attribute name="startdate">2010-05-11T00:00:00</attribute>
    </item>
  </category>
  <category name="Environment">
    <item id="4">
      <attribute name="title">M&amp;A on increase</attribute>
      <attribute name="startdate">2010-05-11T00:00:00</attribute>
    </item>
  </category>
  <category name="Health">
    <item id="2">
      <attribute name="title">FTSE down</attribute>
      <attribute name="startdate">2009-10-01T00:00:00</attribute>
    </item>
  </category>
</latest>

答案 1 :(得分:2)

看起来你应该探索<xsl:key>。这有效地创建了一个hashmap并避免了所有内容的循环。

更新以下是典型的教程:

http://www.learn-xslt-tutorial.com/Working-with-Keys.cfm

答案 2 :(得分:1)

你们循环浏览所有项目并按日期对它们进行排序,然后由于不属于正确的类别而将大部分项目扔掉。

也许这样的事情可能更适合你的情况:

<xsl:variable name="ordereditemlist">
    <xsl:for-each select="/news/itemcategorylist/itemcategory[@categoryid = $categoryid]">
         <xsl:variable name="itemid" select="@itemid"/>

继续从那里收集您实际需要的新闻项目,然后对它们进行排序和复制。

相关问题