簡體   English   中英

使用xsl進行XSLT流式傳輸:迭代正確方法

[英]XSLT streaming with xsl:iterate correct way

我想處理一個161mo數據庫,但是java saxon9he在ram內存為300mb時內存不足,而在.net內存為1700mb時內存耗盡,因此我需要使用流傳輸,因此我使用XMLSpy演示,但我仍然不了解xpath表達式子父邏輯。 我在Windows XP SP3 32bit 4GB RAM上。

    <xsl:iterate select="db_entry">
        <xsl:apply-templates select="db_entry"/>
    </xsl:iterate>

用xsl:iterate或xsl:for-each進行流式傳輸的正確方法是什么? 此數據庫中有將近60000個條目。 我的意思是如何正確編寫此代碼,因為db_entry中的db_entry不起作用。

編輯:

<xsl:template match="databank_export">
<xsl:iterate select="db_entry">
    <xsl:apply-templates select="public_data"/>
    <xsl:text> |</xsl:text>
    <xsl:apply-templates select="text_data"/>
    <xsl:text> |</xsl:text>
    <xsl:apply-templates select="research_data"/>
    <xsl:text>&#10;</xsl:text>
</xsl:iterate>
</xsl:template>

我將db_entry xsl:template替換為xsl:iterate,但是XMLspy無法加載大文件,因此流似乎不起作用。 我做對了還是程序限制還是演示限制?

第2次編輯:我將整個xsl代碼放在這里:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions" xmlns:math="http://www.w3.org/2005/xpath-functions/math" xmlns:array="http://www.w3.org/2005/xpath-functions/array" xmlns:map="http://www.w3.org/2005/xpath-functions/map" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:err="http://www.w3.org/2005/xqt-errors" exclude-result-prefixes="array fn map math xhtml xs err" version="3.0">
    <xsl:output method="text" encoding="UTF-8" indent="yes"/>
    <xsl:mode streamable="yes"/>
    <!--
    <xsl:template match="databank_export">
    -->
    <xsl:template match="/">
        <xsl:apply-templates select="databank_export/copy-of(db_entry)" mode="entry"/>
    </xsl:template>
    <xsl:template match="db_entry" mode="entry">
        <xsl:value-of select="public_data, text_data, research_data" separator=" |"/>
        <xsl:text>&#10;</xsl:text>
    </xsl:template>
    <xsl:template match="public_data">
        <xsl:value-of select="sflname"/>
        <xsl:text>; </xsl:text>
        <xsl:apply-templates select="bdata"/>
        <xsl:text>; </xsl:text>
        <xsl:value-of select="gender"/>
        <xsl:text>; PHOTO : |</xsl:text>
        <xsl:value-of select="name, gender, rating, datatype/@sdatatype, datatype/@sdatasource, bdata/sbdate, bdata/sbdate/@ccalendar" separator=" - "/>
        <xsl:text>|</xsl:text>
        <xsl:value-of select="bdata/sbtime, bdata/sbtime/@sbtime_ampm, bdata/sbtime/@ctimetype, bdata/sbtime/@stimetype, bdata/sbtime/@stmerid, bdata/sbtime/@ctzauto, bdata/sbtime/@jd_ut, bdata/sbtime/@sznabbr, bdata/sbtime/@time_unknown, bdata/sbtime/@itimeaac, bdata/sbtime/@stimeaac" separator=" "/>
        <xsl:text>|</xsl:text>
        <xsl:value-of select="bdata/place, bdata/country, bdata/country/@sctr" separator=", "/>
        <xsl:text>, </xsl:text>
        <xsl:value-of select="bdata/place/@slati, bdata/place/@slong" separator=" "/>
        <xsl:text>|</xsl:text>
        <xsl:value-of select="scollector, seditor, biographer" separator=" "/>
        <xsl:text>|</xsl:text>
        <xsl:value-of select="screationdate, slasteditdate" separator=" "/>
    </xsl:template>
    <xsl:template match="bdata">
        <xsl:value-of select="sbdate/@iday, sbdate/@imonth, sbdate/@iyear" separator="."/>
        <xsl:text>; </xsl:text>
        <xsl:value-of select="sbtime"/>
        <xsl:text>; </xsl:text>
        <xsl:analyze-string select="sbtime/@stmerid" regex="([hm]{{1}})([0-9]{{1,2}})([ew]{{1}})([0-9]{{0,2}})">
            <xsl:matching-substring>
                <xsl:choose>
                    <xsl:when test="regex-group(3) = 'e'">
                        <xsl:text>+</xsl:text>
                    </xsl:when>
                    <xsl:when test="regex-group(3) = 'w'">
                        <xsl:text>-</xsl:text>
                    </xsl:when>
                    <xsl:otherwise>
                        <xsl:text>+</xsl:text>
                    </xsl:otherwise>
                </xsl:choose>
                <xsl:choose>
                    <xsl:when test="regex-group(1) = 'h'">
                        <xsl:number value="regex-group(2)" format="01"/>
                    </xsl:when>
                    <xsl:when test="regex-group(1) = 'm'">
                        <xsl:text>00:</xsl:text>
                        <xsl:number value="regex-group(2)" format="01"/>
                        <xsl:text>:</xsl:text>
                        <xsl:number value="regex-group(4)" format="01"/>
                    </xsl:when>
                    <xsl:otherwise>
                        <xsl:text>+1</xsl:text>
                    </xsl:otherwise>
                </xsl:choose>
            </xsl:matching-substring>
        </xsl:analyze-string>
        <xsl:text>; </xsl:text>
        <xsl:value-of select="place, country" separator=","/>
        <xsl:text>; </xsl:text>
        <xsl:value-of select="place/@slati, place/@slong" separator="; "/>
    </xsl:template>
    <xsl:template match="text_data">
        <xsl:value-of select="shortbiography, wikipedia_link, db_link, sourcenotes" separator="|"/>
    </xsl:template>
    <xsl:template match="research_data">
        <xsl:apply-templates select="categories"/>
        <xsl:text>|</xsl:text>
        <xsl:apply-templates select="relationships"/>
        <xsl:text>|</xsl:text>
        <xsl:value-of select="events/@count"/>
        <xsl:text>|</xsl:text>
        <xsl:apply-templates select="events"/>
    </xsl:template>
    <xsl:template match="categories">
        <xsl:iterate select="category">
            <xsl:value-of select="@cat_id, @db_id, @catnotes" separator=" "/>
            <xsl:text> - </xsl:text>
            <xsl:value-of select="text()"/>
            <xsl:text> |</xsl:text>
        </xsl:iterate>
    </xsl:template>
    <xsl:template match="relationships">
        <xsl:iterate select="relationship">
            <xsl:value-of select="@rel_id, @rel_db_id, @db_id, @relcat" separator=" "/>
            <xsl:text> - </xsl:text>
            <xsl:value-of select="@relnotes, text()" separator=" - "/>
            <xsl:text> |</xsl:text>
        </xsl:iterate>
    </xsl:template>
    <xsl:template match="events">
        <xsl:iterate select="event">
            <xsl:value-of select="@sevcode, @evn_id, @db_id, @evnotes" separator=" "/>
            <xsl:text> |</xsl:text>
            <xsl:apply-templates select="event_data"/>
            <xsl:text> |</xsl:text>
        </xsl:iterate>
    </xsl:template>
    <xsl:template match="event">
        <xsl:apply-templates select="event_data"/>
    </xsl:template>
    <xsl:template match="event_data">
        <xsl:value-of select="sbdate, sbdate/@ccalendar, sbdate_dmy" separator=" "/>
    </xsl:template>

</xsl:stylesheet>

它只能使用一個小的示例文件,但不能使用整個161mb的文件。

最好的祝福。

為了給您提供一個簡單的示例,假設您有很多db_entry元素,但是我們可以安全地假設將單個條目拉入內存不會引起內存問題,那么您可以對這些元素使用copy-of並以與使用流的主要模式:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:math="http://www.w3.org/2005/xpath-functions/math"
    exclude-result-prefixes="xs math"
    version="3.0">

    <xsl:mode streamable="yes"/>

    <xsl:output method="text"/>

    <xsl:template match="/">
        <xsl:apply-templates select="databank_export/copy-of(db_entry)" mode="entry"/>
    </xsl:template>

    <xsl:template match="db_entry" mode="entry">
        <xsl:value-of select="public_data, text_data, research_data" separator=" |"/>
        <xsl:text>&#10;</xsl:text>
    </xsl:template>

</xsl:stylesheet>

轉變例如

<?xml version="1.0" encoding="UTF-8"?>
<databank_export>
   <db_entry>
      <public_data>public data 1</public_data>
      <text_data>text 1</text_data>
      <research_data>research 1</research_data>
   </db_entry>
   <db_entry>
      <public_data>public data 2</public_data>
      <text_data>text 2</text_data>
      <research_data>research 2</research_data>
   </db_entry>
   <db_entry>
      <public_data>public data 3</public_data>
      <text_data>text 3</text_data>
      <research_data>research 3</research_data>
   </db_entry>
   <db_entry>
      <public_data>public data 4</public_data>
      <text_data>text 4</text_data>
      <research_data>research 4</research_data>
   </db_entry>
   <db_entry>
      <public_data>public data 5</public_data>
      <text_data>text 5</text_data>
      <research_data>research 5</research_data>
   </db_entry>
   <db_entry>
      <public_data>public data 6</public_data>
      <text_data>text 6</text_data>
      <research_data>research 6</research_data>
   </db_entry>
   <db_entry>
      <public_data>public data 7</public_data>
      <text_data>text 7</text_data>
      <research_data>research 7</research_data>
   </db_entry>
   <db_entry>
      <public_data>public data 8</public_data>
      <text_data>text 8</text_data>
      <research_data>research 8</research_data>
   </db_entry>
   <db_entry>
      <public_data>public data 9</public_data>
      <text_data>text 9</text_data>
      <research_data>research 9</research_data>
   </db_entry>
   <db_entry>
      <public_data>public data 10</public_data>
      <text_data>text 10</text_data>
      <research_data>research 10</research_data>
   </db_entry>
</databank_export>

public data 1 |text 1 |research 1
public data 2 |text 2 |research 2
public data 3 |text 3 |research 3
public data 4 |text 4 |research 4
public data 5 |text 5 |research 5
public data 6 |text 6 |research 6
public data 7 |text 7 |research 7
public data 8 |text 8 |research 8
public data 9 |text 9 |research 9
public data 10 |text 10 |research 10

Saxon 9.8 EE將使用流式傳輸。

使用xsl:iterate可以使用

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:math="http://www.w3.org/2005/xpath-functions/math"
    exclude-result-prefixes="xs math"
    version="3.0">

    <xsl:mode streamable="yes"/>

    <xsl:output method="text"/>

    <xsl:template match="/">
        <xsl:iterate select="databank_export/db_entry">
            <xsl:apply-templates select="copy-of()" mode="entry"/>
        </xsl:iterate>
    </xsl:template>

    <xsl:template match="db_entry" mode="entry">
        <xsl:value-of select="public_data, text_data, research_data" separator=" |"/>
        <xsl:text>&#10;</xsl:text>
    </xsl:template>

</xsl:stylesheet>

至於您的擴展樣式表,仍然假設將一個db_entry拉入內存以使用不使用流式傳輸的模式正常處理它,我想您需要遵循以下原則

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions" xmlns:math="http://www.w3.org/2005/xpath-functions/math" xmlns:array="http://www.w3.org/2005/xpath-functions/array" xmlns:map="http://www.w3.org/2005/xpath-functions/map" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:err="http://www.w3.org/2005/xqt-errors" exclude-result-prefixes="array fn map math xhtml xs err" version="3.0"
    default-mode="entry">
    <xsl:output method="text" encoding="UTF-8" indent="yes"/>
    <xsl:mode name="start" streamable="yes"/>
    <!--
    <xsl:template match="databank_export">
    -->
    <xsl:template match="/" mode="start">
        <xsl:apply-templates select="databank_export/copy-of(db_entry)" mode="entry"/>
    </xsl:template>
    <xsl:template match="db_entry">
        <xsl:apply-templates select="public_data, text_data, research_data"/>
        <xsl:text>&#10;</xsl:text>
    </xsl:template>
    <xsl:template match="public_data">
        <xsl:value-of select="sflname"/>
        <xsl:text>; </xsl:text>
        <xsl:apply-templates select="bdata"/>
        <xsl:text>; </xsl:text>
        <xsl:value-of select="gender"/>
        <xsl:text>; PHOTO : |</xsl:text>
        <xsl:value-of select="name, gender, rating, datatype/@sdatatype, datatype/@sdatasource, bdata/sbdate, bdata/sbdate/@ccalendar" separator=" - "/>
        <xsl:text>|</xsl:text>
        <xsl:value-of select="bdata/sbtime, bdata/sbtime/@sbtime_ampm, bdata/sbtime/@ctimetype, bdata/sbtime/@stimetype, bdata/sbtime/@stmerid, bdata/sbtime/@ctzauto, bdata/sbtime/@jd_ut, bdata/sbtime/@sznabbr, bdata/sbtime/@time_unknown, bdata/sbtime/@itimeaac, bdata/sbtime/@stimeaac" separator=" "/>
        <xsl:text>|</xsl:text>
        <xsl:value-of select="bdata/place, bdata/country, bdata/country/@sctr" separator=", "/>
        <xsl:text>, </xsl:text>
        <xsl:value-of select="bdata/place/@slati, bdata/place/@slong" separator=" "/>
        <xsl:text>|</xsl:text>
        <xsl:value-of select="scollector, seditor, biographer" separator=" "/>
        <xsl:text>|</xsl:text>
        <xsl:value-of select="screationdate, slasteditdate" separator=" "/>
    </xsl:template>
    <xsl:template match="bdata">
        <xsl:value-of select="sbdate/@iday, sbdate/@imonth, sbdate/@iyear" separator="."/>
        <xsl:text>; </xsl:text>
        <xsl:value-of select="sbtime"/>
        <xsl:text>; </xsl:text>
        <xsl:analyze-string select="sbtime/@stmerid" regex="([hm]{{1}})([0-9]{{1,2}})([ew]{{1}})([0-9]{{0,2}})">
            <xsl:matching-substring>
                <xsl:choose>
                    <xsl:when test="regex-group(3) = 'e'">
                        <xsl:text>+</xsl:text>
                    </xsl:when>
                    <xsl:when test="regex-group(3) = 'w'">
                        <xsl:text>-</xsl:text>
                    </xsl:when>
                    <xsl:otherwise>
                        <xsl:text>+</xsl:text>
                    </xsl:otherwise>
                </xsl:choose>
                <xsl:choose>
                    <xsl:when test="regex-group(1) = 'h'">
                        <xsl:number value="regex-group(2)" format="01"/>
                    </xsl:when>
                    <xsl:when test="regex-group(1) = 'm'">
                        <xsl:text>00:</xsl:text>
                        <xsl:number value="regex-group(2)" format="01"/>
                        <xsl:text>:</xsl:text>
                        <xsl:number value="regex-group(4)" format="01"/>
                    </xsl:when>
                    <xsl:otherwise>
                        <xsl:text>+1</xsl:text>
                    </xsl:otherwise>
                </xsl:choose>
            </xsl:matching-substring>
        </xsl:analyze-string>
        <xsl:text>; </xsl:text>
        <xsl:value-of select="place, country" separator=","/>
        <xsl:text>; </xsl:text>
        <xsl:value-of select="place/@slati, place/@slong" separator="; "/>
    </xsl:template>
    <xsl:template match="text_data">
        <xsl:value-of select="shortbiography, wikipedia_link, db_link, sourcenotes" separator="|"/>
    </xsl:template>
    <xsl:template match="research_data">
        <xsl:apply-templates select="categories"/>
        <xsl:text>|</xsl:text>
        <xsl:apply-templates select="relationships"/>
        <xsl:text>|</xsl:text>
        <xsl:value-of select="events/@count"/>
        <xsl:text>|</xsl:text>
        <xsl:apply-templates select="events"/>
    </xsl:template>
    <xsl:template match="categories">
        <xsl:iterate select="category">
            <xsl:value-of select="@cat_id, @db_id, @catnotes" separator=" "/>
            <xsl:text> - </xsl:text>
            <xsl:value-of select="text()"/>
            <xsl:text> |</xsl:text>
        </xsl:iterate>
    </xsl:template>
    <xsl:template match="relationships">
        <xsl:iterate select="relationship">
            <xsl:value-of select="@rel_id, @rel_db_id, @db_id, @relcat" separator=" "/>
            <xsl:text> - </xsl:text>
            <xsl:value-of select="@relnotes, text()" separator=" - "/>
            <xsl:text> |</xsl:text>
        </xsl:iterate>
    </xsl:template>
    <xsl:template match="events">
        <xsl:iterate select="event">
            <xsl:value-of select="@sevcode, @evn_id, @db_id, @evnotes" separator=" "/>
            <xsl:text> |</xsl:text>
            <xsl:apply-templates select="event_data"/>
            <xsl:text> |</xsl:text>
        </xsl:iterate>
    </xsl:template>
    <xsl:template match="event">
        <xsl:apply-templates select="event_data"/>
    </xsl:template>
    <xsl:template match="event_data">
        <xsl:value-of select="sbdate, sbdate/@ccalendar, sbdate_dmy" separator=" "/>
    </xsl:template>

</xsl:stylesheet>

然后需要使用-im:start運行Saxon 9.8 EE。 上面基本上是您發布的代碼,僅使用default-mode="entry"來確保您編寫的所有模板及其應用模板都屬於名為entry的模式,同時添加了可流start模式,然后使用我之前的的建議

    <xsl:template match="/" mode="start">
        <xsl:apply-templates select="databank_export/copy-of(db_entry)" mode="entry"/>
    </xsl:template>

通過流db_entry元素,但是將每個副本的副本推入不可流模式,在這種模式下可以使用例如

    <xsl:template match="db_entry">
        <xsl:apply-templates select="public_data, text_data, research_data"/>
        <xsl:text>&#10;</xsl:text>
    </xsl:template

如果我是從頭開始編寫的,那我將使用我的較短代碼段中的方法,使未命名的默認模式為可流式,然后將副本推送到命名的不可流式模式,但是鑒於您添加的所有代碼,更易於設置default-mode屬性,然后使用命名模式, start與流作為初始模式。

如前所述,要解決內存問題,只有將成千上萬個db_entry元素組成傳統處理的輸入樹大小時,流和傳統處理混合的整個方法才有意義。 而且它需要Saxon 9.8 EE(或者也許是9.7 EE)作為當前流的唯一實現。

請注意,我沒有努力檢查或更正所有已發布的模板,通常,您可以在嘗試過xsl:iterate許多地方使用xsl:for-each ,或者我更喜歡在其中使用例如<xsl:apply-templates select="event"/>並設置<xsl:template match="event">...</xsl:template> ,以保持代碼模塊化和處理方法的一致性。

馬丁回答了很多問題,但讓我補充幾句話。

您的示例代碼

<xsl:iterate select="db_entry">
    <xsl:apply-templates select="db_entry"/>
</xsl:iterate>

似乎是初學者的錯誤:除非db_entry實際上包含另一個db_entry元素作為子元素,否則應該是

<xsl:iterate select="db_entry">
    <xsl:apply-templates select="."/>
</xsl:iterate>

xsl:iteratexsl:for-each之間的區別在於,使用xsl:for-each ,輸入序列中的每個項目都是獨立於其他項目進行處理的:沒有定義的處理順序,也沒有辦法處理一項可能會影響后續項的處理方式。 使用xsl:iterate可以按順序處理項目,並且(通過使用xsl:next-iteration )可以在處理項目時設置變量/參數,這些變量/參數可以在處理下一個項目時使用。

這種差異與流媒體沒有直接關系。 但是,引入xsl:iterate是因為存在一些用例(例如,計算銀行帳戶上的運行總額),如果沒有這種構造,就很難使它們變得可流式處理。

您編輯的代碼:

<xsl:iterate select="db_entry">
    <xsl:apply-templates select="public_data"/>
    <xsl:text> |</xsl:text>
    <xsl:apply-templates select="text_data"/>
    <xsl:text> |</xsl:text>
    <xsl:apply-templates select="research_data"/>
    <xsl:text>&#10;</xsl:text>
</xsl:iterate>

同樣可以使用xsl:for-each編寫,因為項目的處理完全不依賴於先前項目的處理。 不管怎樣,它都不滿足流式傳輸規則,因為您在迭代主體中進行了三個“向下選擇”,並且只允許一個。 正如Martin所說明的,最簡單的解決方法是為每個db_entry制作一個副本(作為內存中的樹),然后您可以對該副本進行操作而不受任何流約束。

如果您知道三個子元素是按照處理它們的順序出現的,則另一個解決方法是替換:

    <xsl:apply-templates select="public_data"/>
    <xsl:text> |</xsl:text>
    <xsl:apply-templates select="text_data"/>
    <xsl:text> |</xsl:text>
    <xsl:apply-templates select="research_data"/>
    <xsl:text>&#10;</xsl:text>

通過

        <xsl:for-each select="*[
            self::public_data or self::text_data or self::research_data]">
          <xsl:if test="position() ne 1"> |</xsl:if>
          <xsl:apply-templates select="."/>
        </xsl:for-each>
        <xsl:text>&#10;</xsl:text>

(請注意,將豎線放置在除第一個條目之前的每個條目之前,而不是將除最后一個條目之外的每個條目之后放置一個小技巧。這是因為在流式傳輸時,您不知道何時到達終點當您嘗試使代碼可流式傳輸時,類似這樣的小事情變得非常重要。)

正如Martin所說,Altova RaptorXML不支持流傳輸:您將需要為此使用Saxon-EE。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM