Проблема эффективности XSL - нужно решение - PullRequest
1 голос
/ 23 декабря 2009

Ребята, у меня есть интересный сценарий XSL. Пока что мои решения кажутся неэффективными (заметное увеличение времени трансформации), поэтому я подумал, что я это выполнил.

Сценарий Из следующего XML нам нужно получить идентификатор последней новости для каждой категории.

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>

Буду очень признателен за любые ваши идеи.

Спасибо, Alex

Ответы [ 3 ]

5 голосов
/ 23 декабря 2009

Вот как бы я это сделал:

<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> индексирует каждую новость по связанному идентификатору категории. Теперь у вас есть простой способ получить все новости, которые относятся к определенной категории. Остальное просто.

Вывод для меня:

<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>
2 голосов
/ 23 декабря 2009

Похоже, вы должны изучить <xsl:key>. Это эффективно создает хэш-карту и избегает циклического прохождения всего.

обновление Вот типичное руководство:

http://www.learn -xslt-tutorial.com / Рабочий-с-Keys.cfm

1 голос
/ 23 декабря 2009

Вы просматриваете все элементы и сортируете их по дате, прежде чем выбросить большинство из них из-за того, что вы не в нужной категории.

Может быть, что-то подобное может быть более подходящим в вашем случае:

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

И продолжайте оттуда, чтобы собирать только те новости, которые вам действительно нужны, затем сортируйте и копируйте их.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...