使用xsl进行XSLT流式传输:迭代正确的方式

时间:2017-08-01 22:09:48

标签: xml xslt xpath saxon xmlspy

我想处理一个161mo的数据库,但java saxon9内存耗尽300mb的内存和.NET的1700mb ram,所以我需要使用流,所以我使用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>

我用xsl:iterate替换db_entry xsl:template但是XMLspy无法加载大文件,因此看起来流不起作用。 我做得对,还是程序限制或演示限制?

第二次编辑:我会把我的整个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].then(json => {
    Object.keys(json).forEach(key => user[key] = json[key]);
});
)([0-9]{{1,2}})([ew]export class User {
    // properties
    mapResponse(response) {
        Object.keys(response).forEach(key => this[key] = json[key]);
    }
}


getUser(id: number): Promise<User> {
    var user = new User();

    this.http.get('http://localhost:4000/users/1')
        .toPromise()
        .then(response => response.json())
        .then(newUser.mapResponse);

    return user;
}
)([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文件。

最好的问候。

2 个答案:

答案 0 :(得分:2)

为了给你一个简单的例子,假设你有很多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]-im:start)([0-9]{{1,2}})([ew]default-mode="entry")([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>

然后需要使用entry运行Saxon 9.8 EE。以上基本上是您发布的代码,仅使用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属性,然后使用命名模式xsl:for-each与流媒体作为初始模式。

如上所述,为了解决内存问题,如果有数千个xsl:iterate元素构成传统处理输入树的大小,那么流式传输和传统处理混合的整个方法才有意义。它需要Saxon 9.8 EE(或者可能是9.7 EE)作为当前流媒体的唯一实现。

请注意,我没有努力检查或更正您发布的所有模板,一般情况下,您可以在尝试<xsl:apply-templates select="event"/>的许多地方使用<xsl:template match="event">...</xsl:template>,或者我更愿意使用SessionMgrImpl:removeSession例如SessionMgrImpl:removeSessionState并设置 <uses-permission android:name="com.symbol.emdk.permission.EMDK"/> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:launchMode="singleTask" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme"> <uses-library android:name="com.symbol.emdk"/> <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> <intent-filter> <action android:name="com.lisec.emdktest.intentsample.RECVR"/> <category android:name="android.intent.category.DEFAULT"/> </intent-filter> </activity> </application> ,以保持代码模块化和处理方法的一致性。

答案 1 :(得分:2)

马丁已经回答了很多问题,但请允许我补充几句话。

您的示例代码

<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>

(注意除了第一个条目之前在每个条目之前放置一个垂直条的小技巧,而不是在除了最后一条之外的每个条目之后放置。这是因为当你流式传输时,你不知道什么时候你要当你试图使你的代码可以流式传输时,这样的小事变得非常重要。)

正如马丁所说,Altova RaptorXML不支持流式传输:你需要使用Saxon-EE。