【问题标题】:XSLT transform big xml file with less memoryXSLT 用更少的内存转换大 xml 文件
【发布时间】:2017-02-08 13:46:12
【问题描述】:

我在使用 XSLT 转换大数据集(主机上的 60 GB/50000 圆柱体)时遇到问题。 程序在大型机上运行,​​所以我没有得到他需要的 2 GB Headsize。 但我不明白他为什么需要这么多空间,也许有办法用更少的空间进行转换?我对XSLT一无所知,我需要一半时间才能做到这一点^^

我的问题: 在 XML 中有许多我不需要的 XML 标记(在示例 person_id、Iso_laender_code 中),我想过滤,所以我只得到我需要的那些。

我的 XML: 我有很多人的标签:

<ndm_message><message>
    <Person>...</Person>
    <Person>...</Person>
    <Person>...</Person>...

每个人都有诸如姓名、地址等标签以及我不需要的许多标签

<Person>
        <person_id>24</person_id>
        <name>Person's Name</name>
        </titel>
        <Adresse>
              <strasse>Irgendwo</strasse>
              <iso_laender_code>004</iso_laender_code>
        </Adresse>
</Person

我的 XSLT: 我定义了一个白名单并根据白名单检查每个人的任何节点:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<xsl:output method="xml" omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>

<xsi:WhiteList>
    <name>Person</name>
    <name>name</name>
    <name>Adresse</name>
    <name>strasse</name>
 </xsi:WhiteList>

<xsl:template match="/">
    <ndm_message>
    <xsl:for-each select="ndm_message/message/Person">

            <xsl:call-template name="filter" >
                <xsl:with-param name="Knoten" select="."/>
            </xsl:call-template>

    </xsl:for-each>
    </ndm_message>
</xsl:template>

<xsl:template name="filter">
    <xsl:param name="Knoten" />
    <xsl:if test="$Knoten[name()=document('')/*/xsi:WhiteList/*]">

    <xsl:copy>
        <xsl:if test="not(child::*)">
        <xsl:value-of select="$Knoten"/>
        </xsl:if>
        <xsl:for-each select="$Knoten/*">
        <xsl:call-template name="filter" >
            <xsl:with-param name="Knoten" select="."/>
        </xsl:call-template>
        </xsl:for-each>
        <!--  -->
    </xsl:copy>
    </xsl:if>
</xsl:template>

我使用 saxon9.jar 在 Java 中运行 XSLT。

    public static void simpleTransform(String sourcePath, String xsltPath,
                                   String resultDir) {
    System.setProperty("javax.xml.transform.TransformerFactory",
            "net.sf.saxon.TransformerFactoryImpl");
    TransformerFactory tFactory = TransformerFactory.newInstance();
    try {
        Transformer transformer =
            tFactory.newTransformer(new StreamSource(new File(xsltPath)));

        transformer.transform(new StreamSource(new File(sourcePath)),
                              new StreamResult(new File(resultDir)));
    } catch (Exception e) {
        e.printStackTrace();
    }
}

有人知道他为什么需要这么多空间吗?我认为 XSLT 只引用一个 Person 并且标签是递归的,一个 /Person 大约是 32 KB。 也许问题是 StreamSource 和 Result? 有没有其他方法可以使用 XSLT 和更少的空间来做到这一点?

非常感谢 弗洛里安

【问题讨论】:

  • Saxon 9 EE 可能允许您使用流式传输运行 XSLT 3.0 样式表,其中 XSLT 处理器与构建完整 XML 输入树的正常 XSLT 处理模型相反,通过输入流以仅转发模式。但是,这需要 Saxon EE 的许可证并重写 XSLT 以允许这种处理。

标签: xml xslt


【解决方案1】:

这是一个 XSLT 3.0 样式表,您可以将其与 Saxon 9 EE 一起使用,以对您的输入进行streaming processing

<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:output indent="yes"/>
    <xsl:strip-space elements="*"/>

    <xsl:param name="white-list">
        <name>Person</name>
        <name>name</name>
        <name>Adresse</name>
        <name>strasse</name>
    </xsl:param>

    <xsl:template match="ndm_message">
        <xsl:copy>
            <xsl:apply-templates select="message/Person"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="Person//*[not(local-name() = $white-list/name)]"/>

</xsl:stylesheet>

它转换输入样本

<ndm_message>
    <message>
        <Person>
            <person_id>24</person_id>
            <name>Person 24</name>
            <titel>Ein Titel</titel>
            <Adresse>
                <strasse>Strasse 24</strasse>
                <iso_laender_code>004</iso_laender_code>
            </Adresse>
        </Person>
        <Person>
            <person_id>25</person_id>
            <name>Person 25</name>
            <titel>Ein Titel</titel>
            <Adresse>
                <strasse>Strasse 25</strasse>
                <iso_laender_code>004</iso_laender_code>
            </Adresse>
        </Person>
    </message>
</ndm_message>

进入输出样本

<ndm_message>
   <Person>
      <name>Person 24</name>
      <Adresse>
         <strasse>Strasse 24</strasse>
      </Adresse>
   </Person>
   <Person>
      <name>Person 25</name>
      <Adresse>
         <strasse>Strasse 25</strasse>
      </Adresse>
   </Person>
</ndm_message>

至于使用 Java 运行它,我认为使用 XSLT 3.0 和流式传输更好(甚至有必要,请参阅 https://saxonica.plan.io/issues/3120)使用 Saxon 特定 API http://saxonica.com/html/documentation/using-xsl/embedding/s9api-transformation.html 而不是 JAXP。

【讨论】:

    【解决方案2】:

    感谢您的解决方案,但 XSLT Streaming 声音很难,我通常编写 COBOL ^^ 我决定用 Stax-parser 编写一个 Java 程序,并根据文件中的“白名单”检查 XML-Tag。这对我来说更容易,我可以用 UTF-8 读取并用 EBCDIC 写入,所以我在我的 JCL 中保存了一个编码转换步骤 :-) 但非常感谢您的帮助。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-10-14
      • 2015-10-14
      • 2019-01-15
      • 1970-01-01
      • 2019-04-11
      • 2014-11-15
      • 1970-01-01
      相关资源
      最近更新 更多