XSLT递归 - 我该如何改进?

时间:2016-01-26 15:34:32

标签: xml performance xslt recursion

我正在进行大型XML文件(最高15 Mb)的转换,我的转换停止了我的一次递归。

当我使用较小的测试文件时,它工作正常,但对于大文件,Saxon引擎耗尽内存。

我在这里和谷歌搜索并尝试了一些建议的解决方案,但它仍然冻结了我。所以我想知道是否有人可以看一下它并指出一些地方来提高性能,甚至是另外一种方法来实现它。

需要做什么:从输入中我需要列出所有Articlenumbers及其相应的新price-id。这些我需要在以下的XSLT中获取。

我用的是什么: XSLT 2.0 - Saxon 9.3.0.5 - 分配8,5 GB内存

这是我输入的1个产品,最终输入中有大约14.000个:

<catalogus>
    <producten>
        <product>
            <type_id>simple</type_id>
            <zichtbaarheid>4</zichtbaarheid>
            <artikelnummer>12356</artikelnummer>
            <titel>Lorem ipsum dolor sit amet, consecte</titel>
            <omschrijving>Donec metus sem, blandit a metus et, pulvinar tempus nisl. Vivamus
                sollicitudin, nulla ac sollicitudin scelerisque, felis libero eleifend ipsum, sed
                lacinia purus lacus sit amet arcu. Nulla aliquet ipsum maximus dui consequat
                vulputate. Nam vulputate viverra felis ac gravida. Maecenas semper lacinia finibus.
                Aenean non dui tristique, malesuada risus maximus, vulputate urna. Mauris sapien
                magna, euismod ut nisl vel, rutrum sagittis sem. Nam est metus, euismod ac aliquet
                nec, luctus sit amet neque. Nunc arcu libero, imperdiet ut risus sed, eleifend
                semper felis. Proin consectetur leo odio, sed faucibus eros posuere sed. Aenean
                lobortis risus risus, in dictum urna sagittis quis. Pellentesque nec purus semper,
                porttitor lorem sed, scelerisque elit. Sed eleifend lacinia tellus non tempor.
                Vivamus viverra in risus sed venenatis. Aenean semper dignissim nisi ut placerat. </omschrijving>
            <korte_omschrijving>Donec metus sem, blandit a metus et, pulvinar tempus nisl. Vivamus
                sollicitudin, nulla... &lt;a href="#description"&gt;Lees meer</korte_omschrijving>
            <merk>Lorem</merk>
            <merkid>189</merkid>
            <categorie>Main|Diversen|Surprisepakketten</categorie>
            <websites>TBD</websites>
            <voorraad>10</voorraad>
            <is_op_voorraad>1</is_op_voorraad>
            <btw procent="21">2</btw>
            <eigenschappen>
                <productafmetingen>
                    <gewicht type="g">365</gewicht>
                </productafmetingen>
                <kleur>Grijs</kleur>
                <geschiktvoor>Unisex</geschiktvoor>
                <verpakking>Retailverpakking (Karton)</verpakking>
                <materiaal>100% Polyester</materiaal>
            </eigenschappen>
            <systeemAttributen>
                <msrp_enabled>2</msrp_enabled>
                <use_config_min_qty>1</use_config_min_qty>
                <msrp_display_actual_price_type>4</msrp_display_actual_price_type>
                <hide_default_stockstatus>Yes</hide_default_stockstatus>
                <attribute_set_name>Default</attribute_set_name>
                <new_thumbnail_size>100</new_thumbnail_size>
                <opisop>0</opisop>
                <ebizmarts_mark_visited>0</ebizmarts_mark_visited>
            </systeemAttributen>
            <sinds>01-05-15</sinds>
            <gewijzigd>05-01-16</gewijzigd>
            <populariteit>4</populariteit>
            <barcode>646709510084</barcode>
            <image>830302.jpg</image>
            <small_image>830302.jpg</small_image>
            <thumbnail>830302.jpg</thumbnail>
            <media_gallery>830302.jpg;830302_2.jpg;</media_gallery>
            <media_gallery_position>1;2;</media_gallery_position>
            <media_gallery_exclude>0;0;</media_gallery_exclude>
            <nieuw>0</nieuw>
            <maxkorting>58.415599391959184</maxkorting>
            <korting>10</korting>
            <inkoopprijs type="exclBTW">21,4200</inkoopprijs>
            <inkoopactieprijs type="exclBTW">19,4727</inkoopactieprijs>
            <adviesprijs type="inclBTW">39,9500</adviesprijs>
            <verkoopprijs type="exclBTW">31,9835</verkoopprijs>
            <verkoopprijs type="inclBTW">38,7000</verkoopprijs>
            <actieprijs type="exclBTW">29,0759</actieprijs>
            <actieprijs type="inclBTW">35,1818</actieprijs>
            <margeEuro type="exclBTW">12,5107</margeEuro>
            <margeProcent>64.25%</margeProcent>
            <margeEuroActie type="exclBTW">9,6032</margeEuroActie>
            <margeProcentActie>49.32%</margeProcentActie>
            <status>1</status>
        </product>
    </producten>
</catalogus>

ProductPrijzenAccess.xml中的数据:

<dataroot xmlns:od="urn:schemas-microsoft-com:officedata"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:noNamespaceSchemaLocation="ProductenPrijzenAccess.xsd" generated="2016-01-22T16:16:14">
    <Producten>
        <Product-id>Kit-Busine</Product-id>
        <Product-naam>Business Kit</Product-naam>
        <datum-vanaf>2015-02-15T00:00:00</datum-vanaf>
        <datum-tot>2015-10-01T00:00:00</datum-tot>
        <opmerking>Voordeelpakket: B-Grip BH / B-Grip TA / Riemtas</opmerking>
        <Productgroep-id>11</Productgroep-id>
        <webshop>1</webshop>
        <actief>0</actief>
        <LeveranciersID>14</LeveranciersID>
        <Prijzen>
            <Prijzen-id>1052</Prijzen-id>
            <Product-id>Kit-Busine</Product-id>
            <datum-van>2015-02-15T00:00:00</datum-van>
            <datum-tot>2016-02-15T00:00:00</datum-tot>
            <verkoopprijs-ex-BTW>70.2397</verkoopprijs-ex-BTW>
            <inkoopprijs_x0020_ex_x0020_BTW>31.56</inkoopprijs_x0020_ex_x0020_BTW>
        </Prijzen>
        <Prijzen>
            <Prijzen-id>1086</Prijzen-id>
            <Product-id>144744</Product-id>
            <datum-van>2016-02-15T00:00:00</datum-van>
            <datum-tot>2017-10-01T00:00:00</datum-tot>
            <verkoopprijs-ex-BTW>202.4793</verkoopprijs-ex-BTW>
            <incl_x0020_BTW>245</incl_x0020_BTW>
            <inkoopprijs_x0020_ex_x0020_BTW>0</inkoopprijs_x0020_ex_x0020_BTW>
        </Prijzen>
    </Producten>
    <Producten>
        <Product-id>Kit-Care-S</Product-id>
        <Product-naam>Care for it Kit - S</Product-naam>
        <datum-vanaf>2014-12-11T00:00:00</datum-vanaf>
        <datum-tot>2015-10-01T00:00:00</datum-tot>
        <opmerking>Voordeelpakket - B-Grip BH / B-Grip RC / B-Grip HS / ANL S</opmerking>
        <Productgroep-id>11</Productgroep-id>
        <webshop>1</webshop>
        <actief>1</actief>
        <LeveranciersID>14</LeveranciersID>
        <Prijzen>
            <Prijzen-id>1045</Prijzen-id>
            <Product-id>Kit-Care-S</Product-id>
            <datum-van>2014-12-11T00:00:00</datum-van>
            <datum-tot>2014-12-31T00:00:00</datum-tot>
            <verkoopprijs-ex-BTW>82.64</verkoopprijs-ex-BTW>
            <inkoopprijs_x0020_ex_x0020_BTW>37.35</inkoopprijs_x0020_ex_x0020_BTW>
        </Prijzen>
    </Producten>
</dataroot>

我使用的XSLT递归:

<xsl:call-template name="NieuwePrijzenIDs">
                <!-- Get the current price-id's from external file from Access and sort them. -->
                <xsl:with-param name="AlleHuidigePrijsIDs">
                    <xsl:for-each
                        select="document('ProductenPrijzenAccess.xml')/dataroot/Producten/Prijzen">
                        <xsl:sort data-type="number" order="ascending" select="child::Prijzen-id"/>
                        <xsl:element name="Prijzen-id">
                            <xsl:value-of select="Prijzen-id"/>
                        </xsl:element>
                    </xsl:for-each>
                </xsl:with-param>

                <!-- Parameter with total number of products that need a new Price-id. -->
                <xsl:with-param name="TotaalAantalArtikelenToevoegen"
                    select="count(producten/product)"/>

                <!-- Parameter with all products that need a new Price-id. -->
                <xsl:with-param name="ArtikelenToevoegen">
                    <xsl:for-each select="producten/product">
                        <xsl:element name="Artikelnummer">
                            <xsl:value-of select="artikelnummer"/>
                        </xsl:element>
                    </xsl:for-each>
                </xsl:with-param>

            </xsl:call-template>

<xsl:template name="NieuwePrijzenIDs">
            <xsl:param name="AlleHuidigePrijsIDs"/>
            <xsl:param name="TotaalAantalArtikelenToevoegen"/>
            <xsl:param name="ArtikelenToevoegen"/>


            <xsl:element name="Prijzen">
                <xsl:call-template name="NieuwePrijzenIDinhoud">
                    <xsl:with-param name="LaatsteGebruikteNummer"
                        select="$AlleHuidigePrijsIDs/Prijzen-id[position() = last()]"/>
                    <xsl:with-param name="TotaalAantalArtikelenToevoegen"
                        select="$TotaalAantalArtikelenToevoegen"/>
                    <xsl:with-param name="ArtikelenToevoegen" select="$ArtikelenToevoegen"/>
                </xsl:call-template>
            </xsl:element>


        </xsl:template>

        <xsl:template name="NieuwePrijzenIDinhoud">
            <xsl:param name="LaatsteGebruikteNummer"/>
            <xsl:param name="TotaalAantalArtikelenToevoegen"/>
            <xsl:param name="ArtikelenToevoegen"/>

            <xsl:choose>
                <!-- If the total of products that needs to be added is bigger then 1, go on. -->
                <xsl:when test="$TotaalAantalArtikelenToevoegen &gt; 1">
                    <xsl:element name="PrijzenID">
                        <xsl:attribute name="Artikelnummer">
                            <xsl:value-of select="$ArtikelenToevoegen/Artikelnummer[1]"/>
                        </xsl:attribute>

                        <xsl:value-of select="$LaatsteGebruikteNummer + 1"/>
                    </xsl:element>

                    <xsl:call-template name="NieuwePrijzenIDinhoud">
                        <xsl:with-param name="TotaalAantalArtikelenToevoegen"
                            select="$TotaalAantalArtikelenToevoegen - 1"/>
                        <xsl:with-param name="LaatsteGebruikteNummer"
                            select="$LaatsteGebruikteNummer + 1"/>
                        <xsl:with-param name="ArtikelenToevoegen">
                            <xsl:copy-of select="$ArtikelenToevoegen/Artikelnummer[position() != 1]"/>
                        </xsl:with-param>
                    </xsl:call-template>
                </xsl:when>
                <xsl:otherwise>
                    <xsl:element name="PrijzenID">
                        <xsl:attribute name="Artikelnummer">
                            <xsl:value-of select="$ArtikelenToevoegen/Artikelnummer[1]"/>
                        </xsl:attribute>

                        <xsl:value-of select="$LaatsteGebruikteNummer + 1"/>
                    </xsl:element>
                </xsl:otherwise>
            </xsl:choose>

        </xsl:template>

输出应为:

<Prijzen>
      <PrijzenID Artikelnummer="12356">1177</PrijzenID>
</Prijzen>

1 个答案:

答案 0 :(得分:2)

您可能希望显示所有输入文档的小但有代表性的样本,然后解释您想要的关系和结果,我不明白为什么口头描述“从输入我需要列出所有条款数字和他们相应的新price-id“需要递归。

对于发布的代码片段,您似乎在

等位置构建中间结果元素
            <xsl:with-param name="AlleHuidigePrijsIDs">
                <xsl:for-each
                    select="document('ProductenPrijzenAccess.xml')/dataroot/Producten/Prijzen">
                    <xsl:sort data-type="number" order="ascending" select="child::Prijzen-id"/>
                    <xsl:element name="Prijzen-id">
                        <xsl:value-of select="Prijzen-id"/>
                    </xsl:element>
                </xsl:for-each>
            </xsl:with-param>

我想知道你是否不能简单地对文档进行一次排序并使用那个已排序的文档,例如使用全局变量

<xsl:variable name="sorted-prices" as="element(Prijzen-id)">
  <xsl:perform-sort select="document('ProductenPrijzenAccess.xml')/dataroot/Producten/Prijzen/Prijzen-id">
    <xsl:sort select="xs:decimal(.)"/>
  </xsl:perform-sort>
</xsl:variable>

然后,您将拥有这些Prijzen-id元素的已排序序列,然后可以将其与例如<xsl:with-param name="AlleHuidigePrijsIDs" select="$sorted-prices"/>元素一起使用。 <xsl:with-param name="ArtikelenToevoegen"> <xsl:for-each select="producten/product"> <xsl:element name="Artikelnummer"> <xsl:value-of select="artikelnummer"/> </xsl:element> </xsl:for-each> </xsl:with-param> 或直接使用全局变量。

同样在

<xsl:with-param name="ArtikelenToevoegen" select="producten/product/artikelnummer"/>

你构建了新元素(被承认,名称略有不同),似乎只需用<xsl:value-of select="$ArtikelenToevoegen[1]/>选择现有元素就可以避免构造新元素。当然,需要调整模板,然后选择<xsl:value-of select="$ArtikelenToevoegen/Artikelnummer[1]"/>而不是 <xsl:with-param name="ArtikelenToevoegen"> <xsl:copy-of select="$ArtikelenToevoegen/Artikelnummer[position() != 1]"/> </xsl:with-param>

然后你再次在

中构建节点的副本
<xsl:with-param name="ArtikelenToevoegen" select="$ArtikelenToevoegen[position() != 1]"/>

我想知道<xsl:variable name="max-id" select="max(document('ProductenPrijzenAccess.xml')/dataroot/Producten/Prijzen/Prijzen-id/xs:decimal(.))"/> 是否不足以简单地使用现有节点。

至于一种全新的方法,可能只是简单地做

<xsl:template match="/">
  <Prijzen>
    <xsl:apply-templates select="catalogus/producten/product/artikelnummer"/>
  </Prijzen>
</xsl:template>

<xsl:template match="artikelnummer">
  <PrijzenID Artikelnummer="{.}">
    <xsl:value-of select="$max-id + position()"/>
  </PrijzenID>
</xsl:template>

在全局变量中,然后

{{1}}

就足够了。