2

次のコードを使用して、大きな xml ストリームを別のストリームに変換しています。

 import java.io.ByteArrayInputStream;
 import java.io.InputStreamReader;
 import java.io.OutputStreamWriter;
 import java.io.PrintWriter;
 import java.io.Writer;
 import javax.xml.stream.XMLEventReader;
 import javax.xml.stream.XMLEventWriter;
 import javax.xml.stream.XMLInputFactory;
 import javax.xml.stream.XMLOutputFactory;
 import javax.xml.stream.XMLStreamException;
 import javax.xml.stream.XMLStreamReader;
 import javax.xml.stream.events.XMLEvent;
 import javax.xml.transform.Result;
 import javax.xml.transform.Source;
 import javax.xml.transform.Transformer;
 import javax.xml.transform.TransformerFactory;
 import javax.xml.transform.stax.StAXResult;
 import javax.xml.transform.stax.StAXSource;

 public class TryMe 
 {
   public static void main (final String[] args)
   {
    XMLInputFactory inputFactory = null;
    XMLEventReader eventReaderXSL = null;
    XMLEventReader eventReaderXML = null;
    XMLOutputFactory outputFactory = null;
    XMLEventWriter eventWriter = null;
    Source XSL = null;
    Source XML = null;
    inputFactory = XMLInputFactory.newInstance();
    outputFactory = XMLOutputFactory.newInstance();
    inputFactory.setProperty("javax.xml.stream.isSupportingExternalEntities", Boolean.TRUE);
    inputFactory.setProperty("javax.xml.stream.isNamespaceAware", Boolean.TRUE);
    inputFactory.setProperty("javax.xml.stream.isReplacingEntityReferences", Boolean.TRUE);
    try
    {
        eventReaderXSL = inputFactory.createXMLEventReader("my_template",
                new InputStreamReader(TryMe.class.getResourceAsStream("my_template.xsl")));
        eventReaderXML = inputFactory.createXMLEventReader("big_one", new InputStreamReader(
                TryMe.class.getResourceAsStream("big_one.xml")));
    }
    catch (final javax.xml.stream.XMLStreamException e)
    {
        System.out.println(e.getMessage());
    }

    // get a TransformerFactory object
    final TransformerFactory transfFactory = TransformerFactory.newInstance();

    // define the Source object for the stylesheet
    try
    {
        XSL = new StAXSource(eventReaderXSL);
    }
    catch (final javax.xml.stream.XMLStreamException e)
    {
        System.out.println(e.getMessage());
    }
    Transformer tran2 = null;
    // get a Transformer object
    try
    {

        tran2 = transfFactory.newTransformer(XSL);
    }
    catch (final javax.xml.transform.TransformerConfigurationException e)
    {
        System.out.println(e.getMessage());
    }

    // define the Source object for the XML document
    try
    {
        XML = new StAXSource(eventReaderXML);
    }
    catch (final javax.xml.stream.XMLStreamException e)
    {
        System.out.println(e.getMessage());
    }

    // create an XMLEventWriter object
    try
    {

        eventWriter = outputFactory.createXMLEventWriter(new OutputStreamWriter(System.out));
    }
    catch (final javax.xml.stream.XMLStreamException e)
    {
        System.out.println(e.getMessage());
    }

    // define the Result object
    final Result XML_r = new StAXResult(eventWriter);

    // call the transform method
    try
    {

        tran2.transform(XML, XML_r);
    }
    catch (final javax.xml.transform.TransformerException e)
    {
        System.out.println(e.getMessage());
    }

    // clean up
    try
    {
        eventReaderXSL.close();
        eventReaderXML.close();
        eventWriter.close();
    }
    catch (final javax.xml.stream.XMLStreamException e)
    {
        System.out.println(e.getMessage());
    }
}

}

my_template は次のようなものです。

<xsl:stylesheet version = '1.0' 
     xmlns:xsl='http://www.w3.org/1999/XSL/Transform'>

<xsl:preserve-space elements="*"/>

<xsl:template match="@*|node()">
  <xsl:copy>
    <xsl:apply-templates select="@*|node()"/>
  </xsl:copy>
</xsl:template>


<xsl:template match="@k8[parent::point]">
  <xsl:attribute name="k8">
    <xsl:value-of select="'xxxxxxxxxxxxxx'"/>
  </xsl:attribute>
</xsl:template>

</xsl:stylesheet>

そしてxmlは長い長いリストです

<data>
  <point .... k8="blablabla" ... ></point>
  <point .... k8="blablabla" ... ></point>
  <point .... k8="blablabla" ... ></point>
  ....
  <point .... k8="blablabla" ... ></point>
</data>

入力ストリームの処理中に恒等変換器を使用すると ( transFactory(XSL) の代わりに tranfsFactory.newTransformer() を使用)、出力が生成されます。代わりに、私のテンプレートでは方法がありません..トランスフォーマーはすべての入力を読み取り、出力の生成を開始します(もちろん、大きなストリームでは、結果の前にメモリ不足が発生することがよくあります.

何か案が??私はおかしくなりました..コード/xsltの何が問題なのか理解できません

よろしくお願いします!

4

6 に答える 6

8

XSLT 1.0 および 2.0 は、完全な XML のツリー データ モデルで動作するため、通常、XSLT 1.0 および 2.0 プロセッサは、完全な XML 入力ドキュメントをツリーに読み取り、結果ツリーを作成してからシリアル化します。StAX を使用すると XSLT の動作が変わると思われるようですが、そうではないと思います。スタイルシートには先行または先行兄弟のような複雑な XPath ナビゲーターが必要になる可能性があるため、XSLT プロセッサはツリーを構築します。

ただし、Java を使用する場合は、Saxon 9.3 とその実験的な XSLT 3.0 ストリーミング サポートを調べることができます。そうすれば、非常に大きな XML 入力ドキュメントを処理するときにメモリ不足になることはありません。

XSLT で異常な部分は です<xsl:template match="@k8[parent::point]">。これは通常、単に次のように記述され<xsl:template match="point/@k8">ますが、それによってパフォーマンスが変わるかどうかを XSLT プロセッサでテストする必要があります。

于 2011-04-06T15:41:45.260 に答える
3

XSLT を使用することはおそらく最善の方法ではありません。他の人が指摘したように、プロセッサは出力を書き出す前にドキュメント全体をメモリに読み込む必要があると指摘しています。SAX パーサーを使用して各ノードを順次読み取り、必要な変換を実行し (必要に応じてデータ駆動型マッピングを使用)、変換されたデータを書き出すことを検討してください。これにより、ドキュメント ツリー全体をメモリ内に作成する必要がなくなり、複雑なドキュメントを作成して書き出す必要がないため、処理が大幅に高速化されます。

出力形式がシンプルで安定しているかどうかを自問してから、XSLT の使用を再検討してください。通常のデータの大規模なデータセットの場合、XML が情報の転送に適したファイル形式であるかどうかを検討することもできます。

于 2011-04-06T16:25:57.017 に答える
2

トランスフォーマーはすべての入力を読み取り、出力の生成を開始します(もちろん、大規模なストリームでは、結果の前にメモリ不足が発生することがよくあります。

何か案が?

この作業が完了するまでに時間がかかりすぎる場合は、出力ファイルの処理を開始する前に、入力ファイル全体を読み取らないように、タスクへのアプローチを再設計する必要があります。コードを魔法のように高速化するために微調整できるものは何もありません。アルゴリズムのコアに対処する必要があります。

于 2011-04-06T15:24:26.667 に答える
1

XSL で行っている変換はどの程度複雑ですか? StAX だけを使用して同じ変換を行うことができますか?

StAX を使用すると、特定のノードに一致するパーサーを作成し、その時点で書き込んでいる出力ストリーム内のノードを挿入、変更、または削除するのは非常に簡単です。したがって、変換に XSL を使用する代わりに、StAX を単独で使用することもできます。この方法では、API のストリーミングの性質を利用でき (大きなツリーをメモリにバッファリングしない)、メモリの問題は発生しません。

偶然にも、別の質問に対するこの最近の回答がその助けになるかもしれません。

于 2011-04-06T16:38:44.180 に答える
1

他の人が指摘しているように、Stax を使用しても XSLT の動作は変わりません。作業を開始する前に、最初にすべてを読み取ります。非常に大きなファイルを扱う必要がある場合は、XSLT 以外のものを使用する必要があります。

次に、さまざまなオプションがあります。

  • Java で SAX パイプラインを使用して変換を書き直します。
  • XSLT のストリーミング版であるSTX/Joostを使用して変換を書き直します。
  • Scala のFreetle XML 変換フレームワークを使用して変換を書き直します。
于 2011-11-12T21:38:31.127 に答える