2

dom4j を使用してストリームから一度に 1 つの XML ドキュメントを読み取り、処理してから、ストリーム上の次のドキュメントに進みます。残念ながら、dom4j の SAXReader (裏で JAXP を使用) は読み取りを続け、次のドキュメント要素を停止します。

ドキュメント要素の終わりを見つけたら、SAXReader にストリームの読み取りを停止させる方法はありますか? これを達成するためのより良い方法はありますか?

4

6 に答える 6

1

いくつかの内部 JAXP クラスを使用して、いくつかの体操でこれを機能させることができました。

  • XMLNSDocumentScannerImpl のサブクラスであるカスタム スキャナーを作成する
    • XMLNSDocumentScannerImpl.Driver の実装であるカスタム ドライバーをカスタム スキャナー内に作成します。カスタム スキャナーは、宣言または要素を検出すると END_DOCUMENT を返します。fElementScanner.getCurrentEntity() から ScannedEntity を取得します。エンティティに PushbackReader がある場合は、エンティティ バッファー内の残りの未読文字をリーダーにプッシュ バックします。
    • コンストラクターで、fTrailingMiscDriver をこのカスタム ドライバーのインスタンスに置き換えます。
  • XIncludeAwareParserConfiguration のサブクラスであるカスタム構成クラスを作成します。これは、ストック DOCUMENT_SCANNER をコンストラクター内のこのカスタム スキャナーのインスタンスに置き換えます。
  • このカスタム構成クラスのインスタンスを「com.sun.org.apache.xerces.internal.xni.parser.XMLParserConfiguration」プロパティとしてインストールして、dom4j の SAXReader クラスが JAXP XMLReader を作成しようとしたときにインスタンス化されるようにします。
  • Reader を dom4j の SAXReader.read() メソッドに渡すときは、デフォルトの 1 文字よりもかなり大きなバッファ サイズを PushbackReader に指定してください。Apache2 の JAXP コピー内の XMLEntityManager のデフォルト バッファ サイズをサポートするには、少なくとも 8192 で十分です。

これは、内部 JAXP クラスのサブクラス化を伴うため、最もクリーンなソリューションではありませんが、機能します。

于 2008-10-27T22:13:03.537 に答える
0

私は以前、非常に単純な解析機能を備えた自分で作成した別のリーダーでベースリーダーをラップすることによってこれを行いました。ドキュメントの終了タグを知っていると仮定すると、ラッパーは単に「</MyDocument>」などの一致を解析します。EOFを返すことを検出したとき。最初の開始タグを解析し、一致する終了タグでEOFを返すことにより、ラッパーを適応させることができます。ドキュメントタグを使用したドキュメントがないため、実際に終了タグのレベルを検出する必要がないことがわかりました。したがって、終了タグが最初に出現すると、ドキュメントが終了することが保証されました。

私が思い出したように、トリックの1つは、DOMリーダーが入力ソースを閉じるため、ラッパーブロックをclose()にすることでした。

したがって、Readerの入力が与えられると、コード次のようになります。

SubdocReader sdr=new SubdocReader(input);
while(!sdr.eof()) {
    sdr.next();
    // read doc here using DOM
    // then process document
    }
input.close();

EOFが検出されると、eof()メソッドはtrueを返します。next()メソッドは、read()に対して-1を返すのを停止するようにリーダーにフラグを立てます。

うまくいけば、これはあなたを有用な方向に向けます。

- キウイ。

于 2008-10-29T01:14:54.527 に答える
0

入力ストリームを内部バッファに読み込みます。予想される合計ストリームサイズに応じて、ストリーム全体を読み取ってから解析するか、1つのxmlと次のxmlの間の境界を検出します(

1つのxmlを持つストリームと複数のxmlを持つストリームの処理の唯一の本当の違いは、バッファーと分割ロジックです。

于 2008-11-05T02:28:56.817 に答える
0

最初にドキュメントをストリームに配置する責任があると仮定すると、何らかの方法でドキュメントを簡単に区切ることができます。例えば:

// XML 文字として無効な値であれば何でも構いません。
static final char DOC_TERMINATOR=4;

BOOL addDocumentToStream(BufferedWriter streamOut, char xmlData[])
{
  streamOut.write(xmlData);
  streamOut.write(DOC_TERMINATOR);
}

次に、ストリームから読み取るときに、DOC_TERMINATOR が検出されるまで配列に読み取ります。

char *getNextDocument(BufferedReader streamIn)
{
  StringBuffer バッファ = 新しい StringBuffer();
  int 文字;

  while (真)
  {
    文字 = streamIn.read();
    if (文字 == DOC_TERMINATOR)
      壊す;

    buffer.append(文字);
  }
  buffer.toString().toCharArray(); を返します。
}

4 は無効な文字値であるため、明示的に追加する場合を除いて遭遇することはありません。したがって、ドキュメントを分割できます。あとは、SAX への入力用に結果の char 配列をラップするだけです。

...
  XMLReader xmlReader = XMLReaderFactory.createXMLReader();
...
  while (真)
  {
    char xmlDoc = getNextDocument(streamIn);

    if (xmlDoc.length == 0)
      壊す;

    InputSource saxInputSource = new InputSource(new CharArrayReader(xmlDoc));
    xmlReader.parse(saxInputSource);
  }
...

長さ 0 のドキュメントを取得すると、ループが終了することに注意してください。これは、最後のドキュメントの後に 2 番目の DOC_TERMINATOR を追加して、getNextDocument() でストリームの終了を検出するために何かを追加する必要があることを意味します。

于 2008-10-27T23:53:48.870 に答える
0

ほとんどの場合、同時に複数のドキュメントを同じストリームに入れたくありません。SAXReader は、最初のドキュメントの最後に到達したときに停止するほどスマートではないと思います。このように同じストリームに複数のドキュメントが必要なのはなぜですか?

于 2008-10-23T19:28:14.297 に答える
0

アダプターを追加する必要があると思います。ストリームをラップし、次のドキュメントの先頭が表示されたときにファイルの終わりを返すようにする必要があります。私の知る限り、書かれているパーサーは、ファイルの終わりまたはエラーまで続きます...そして別のものを見る<?xml version="1.0"?>と確かにエラーになります。

于 2008-10-23T21:37:17.033 に答える