XSLT转换大xml文件,内存较少

时间:2017-02-08 13:46:13

标签: xml xslt

我遇到XSLT问题转换大数据集(主机上为60 GB / 50000 Cylinder)。 该程序在Mainframe上运行,所以我没有得到他需要的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和更少的空间吗?

非常感谢 弗洛里安

2 个答案:

答案 0 :(得分:2)

这是一个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。

答案 1 :(得分:0)

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