使用 xsl:iterate 正确方式的 XSLT 流式传输
XSLT streaming with xsl:iterate correct way
我想处理一个 161mo 的数据库,但是 java saxon9he 运行 在 300mb ram 和 .NET 在 1700mb ram 时内存不足,所以我需要使用流式处理,所以我使用XMLSpy 演示,但我仍然不明白 xpath 表达式的子父逻辑。我在 windows xp sp3 32 位 4gb 内存上。
<xsl:iterate select="db_entry">
<xsl:apply-templates select="db_entry"/>
</xsl:iterate>
使用 xsl:iterate 或 xsl:for 进行流式传输的正确方法是什么?该数据库中有近 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> </xsl:text>
</xsl:iterate>
</xsl:template>
我将 db_entry xsl:template 替换为 xsl:iterate,但 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> </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> </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> </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> </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>
然后需要 运行 Saxon 9.8 EE 和 -im:start
。以上基本上是您发布的代码,仅使用 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> </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:iterate
和xsl:for-each
的区别在于xsl:for-each
,输入序列中的每一项都是独立处理的:没有定义的处理顺序,并且一个项目的处理不可能影响后续项目的处理方式。使用xsl:iterate
,项目按顺序处理,并且(通过使用xsl:next-iteration
)您可以在处理一个项目时设置variables/parameters,在处理下一个项目时可以使用。
这种差异与流媒体没有直接关系;然而 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> </xsl:text>
</xsl:iterate>
也可以用 xsl:for-each
来写,因为一个项目的处理不以任何方式依赖于前面项目的处理。然而,无论哪种方式,它都不满足流式规则,因为您在迭代主体中制作三个 "downward selections",而您只允许一个。正如 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> </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> </xsl:text>
(请注意在除第一个条目之外的每个条目之前放置一个竖线的小技巧,而不是在除最后一个条目之外的每个条目之后放置它。那是因为当你在流式传输时,你不知道你什么时候即将结束。当您尝试使您的代码可流化时,像这样的小事情变得非常重要。)
正如 Martin 所说,Altova RaptorXML 不支持流式传输:为此您需要使用 Saxon-EE。
我想处理一个 161mo 的数据库,但是 java saxon9he 运行 在 300mb ram 和 .NET 在 1700mb ram 时内存不足,所以我需要使用流式处理,所以我使用XMLSpy 演示,但我仍然不明白 xpath 表达式的子父逻辑。我在 windows xp sp3 32 位 4gb 内存上。
<xsl:iterate select="db_entry">
<xsl:apply-templates select="db_entry"/>
</xsl:iterate>
使用 xsl:iterate 或 xsl:for 进行流式传输的正确方法是什么?该数据库中有近 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> </xsl:text>
</xsl:iterate>
</xsl:template>
我将 db_entry xsl:template 替换为 xsl:iterate,但 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> </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> </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> </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> </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>
然后需要 运行 Saxon 9.8 EE 和 -im:start
。以上基本上是您发布的代码,仅使用 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> </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:iterate
和xsl:for-each
的区别在于xsl:for-each
,输入序列中的每一项都是独立处理的:没有定义的处理顺序,并且一个项目的处理不可能影响后续项目的处理方式。使用xsl:iterate
,项目按顺序处理,并且(通过使用xsl:next-iteration
)您可以在处理一个项目时设置variables/parameters,在处理下一个项目时可以使用。
这种差异与流媒体没有直接关系;然而 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> </xsl:text>
</xsl:iterate>
也可以用 xsl:for-each
来写,因为一个项目的处理不以任何方式依赖于前面项目的处理。然而,无论哪种方式,它都不满足流式规则,因为您在迭代主体中制作三个 "downward selections",而您只允许一个。正如 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> </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> </xsl:text>
(请注意在除第一个条目之外的每个条目之前放置一个竖线的小技巧,而不是在除最后一个条目之外的每个条目之后放置它。那是因为当你在流式传输时,你不知道你什么时候即将结束。当您尝试使您的代码可流化时,像这样的小事情变得非常重要。)
正如 Martin 所说,Altova RaptorXML 不支持流式传输:为此您需要使用 Saxon-EE。