XSL 转换 300M 与 xsltproc(内存不足)



我需要转换XML文件(将所有ITEM元素的PRODUCTNO设置为ITEM_ID)。没有换行符,文件内容是一长行。

<SHOP>
<ITEM>
  <NAME>...</NAME>
  <ITEM_ID>11</ITEM_ID>
  <PRODUCTNO>22</PRODUCTNO>
  <TAG>...</TAG>
</ITEM>
....
</SHOP

第一次尝试是使用 xsltproc,但我以 300M 文件的"杀死"(出于记忆,消耗 2G)结束。

<?xml version='1.0' encoding='ISO-8859-1'?>
 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output method="xml" indent="yes"/>
 <xsl:strip-space elements="*"/>
 <xsl:template match="@*|node()">
  <xsl:copy>
   <xsl:apply-templates/>
  </xsl:copy>
 </xsl:template>
 <xsl:template match="ITEM_ID">
  <ITEM_ID><xsl:value-of select = "../PRODUCTNO" /></ITEM_ID>
 </xsl:template>
</xsl:stylesheet>

好吧,我今天学习 XSL :)是否可以写得更好(内存效率更高),或者必须使用其他处理器。由于逐行处理,我尝试了 sed 但没有成功。

sed -r -e 's///g'

Xsl 处理器会更好。

Martin Honnen 关于 XSL 3.0 的答案是正确的!
最后,由于许可证的原因,我使用了SED。

我的解决方案是:

  1. 将每个项目放在一行上
  2. 做替换(ITEM_ID总是在PRODUCTNO前面)

因此,SED 解决方案如下所示:

cat file.xml | sed -e 's/<ITEM>/n<ITEM>/g' | sed -e 's/<ITEM_ID>(.*)</ITEM_ID>(.*)<PRODUCTNO>(.*)</PRODUCTNO>/<ITEM_ID>3</ITEM_ID>2<PRODUCTNO>3</PRODUCTNO>/g'

它不如SLT处理安全,但速度/内存消耗获胜。

使用流式处理和复制的混合,您可以在 XSLT 3.0 中使用

<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:param name="STREAMABLE" static="yes" as="xs:boolean" select="true()"/>
    <xsl:mode _streamable="{$STREAMABLE}" on-no-match="shallow-copy"/>
    <xsl:mode name="change" on-no-match="shallow-copy"/>
    <xsl:template match="ITEM">
        <xsl:apply-templates select="copy-of()" mode="change"/>
    </xsl:template>
    <xsl:template match="ITEM_ID" mode="change">
        <xsl:copy>
            <xsl:value-of select="../PRODUCTNO"/>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

这将在流模式下处理初始输入文档,然后创建每个ITEM元素的副本,以在其上使用正常的模板匹配来转换ITEM_ID

要使用 XSLT 3.0 和流式处理,您需要使用 Saxon 9.7 EE(可从 http://www.saxonica.com/download/download_page.xml 获得)或 Exselt (可从 http://exselt.net/获得)。

另一方面,如果您可以在当今的台式 PC 上授予它足够的内存,那么使用普通 XSLT 1.0 或 2.0 处理器 300 MB 听起来是可行的。

最新更新