6

xml は次のようになります。

<statements>
   <statement account="123">
      ...stuff...
   </statement>
   <statement account="456">
      ...stuff...
   </statement>
</statements>

一度に 1 つの " " を処理するために stax を使用し<statement>ていますが、それが機能しています。「123.xml」と「456.xml」を作成したり、アカウントでインデックス付けされたデータベース テーブルにロードしたりできるように、ステートメント ノード全体を文字列として取得する必要があります。

このアプローチの使用: http://www.devx.com/Java/Article/30298/1954

私はこのようなことをしようとしています:

String statementXml = staxXmlReader.getNodeByName("statement");

//load statementXml into database
4

6 に答える 6

11

私は同様の仕事をしていましたが、元の質問は1年以上前のものですが、満足のいく答えを見つけることができませんでした. これまでで最も興味深い回答は Blaise Doughan の回答でしたが、期待している XML で実行できませんでした (基になるパーサーのパラメーターによって変更される可能性があります)。ここでは、非常に単純化された XML を示します。

<many-many-tags>
    <description>
        ...
        <p>Lorem ipsum...</p>
        Devils inside...
        ...
    </description>
</many-many-tags>

私の解決策:

public static String readElementBody(XMLEventReader eventReader)
    throws XMLStreamException {
    StringWriter buf = new StringWriter(1024);

    int depth = 0;
    while (eventReader.hasNext()) {
        // peek event
        XMLEvent xmlEvent = eventReader.peek();

        if (xmlEvent.isStartElement()) {
            ++depth;
        }
        else if (xmlEvent.isEndElement()) {
            --depth;

            // reached END_ELEMENT tag?
            // break loop, leave event in stream
            if (depth < 0)
                break;
        }

        // consume event
        xmlEvent = eventReader.nextEvent();

        // print out event
        xmlEvent.writeAsEncodedUnicode(buf);
    }

    return buf.getBuffer().toString();
}

使用例:

XMLEventReader eventReader = ...;
while (eventReader.hasNext()) {
    XMLEvent xmlEvent = eventReader.nextEvent();
    if (xmlEvent.isStartElement()) {
        StartElement elem = xmlEvent.asStartElement();
        String name = elem.getName().getLocalPart();

        if ("DESCRIPTION".equals(name)) {
            String xmlFragment = readElementBody(eventReader);
            // do something with it...
            System.out.println("'" + fragment + "'");
        }
    }
    else if (xmlEvent.isEndElement()) {
        // ...
    }
}

抽出された XML フラグメントには、空白やコメントを含む、抽出された完全な本文コンテンツが含まれることに注意してください。必要に応じてそれらをフィルタリングするか、バッファ サイズをパラメータ化できるようにすることは、コードを簡潔にするために省略されています。

'
    <description>
        ...
        <p>Lorem ipsum...</p>
        Devils inside...
        ...
    </description>
    '
于 2012-07-25T13:44:22.057 に答える
6

これにはStaxを使用できます。ステートメントのStart要素までXMLStreamReaderを進めるだけです。アカウント属性を確認して、ファイル名を取得します。次に、javax.xml.Transform APIを使用して、StaxSourceをファイルをラッピングするStreamResultに変換します。これにより、XMLStreamReaderが進み、このプロセスを繰り返すだけです。

import java.io.File;
import java.io.FileReader;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamReader;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stax.StAXSource;
import javax.xml.transform.stream.StreamResult;

public class Demo {

    public static void main(String[] args) throws Exception  {
        XMLInputFactory xif = XMLInputFactory.newInstance();
        XMLStreamReader xsr = xif.createXMLStreamReader(new FileReader("input.xml"));
        xsr.nextTag(); // Advance to statements element

        while(xsr.nextTag() == XMLStreamConstants.START_ELEMENT) {
            TransformerFactory tf = TransformerFactory.newInstance();
            Transformer t = tf.newTransformer();
            File file = new File("out" + xsr.getAttributeValue(null, "account") + ".xml");
            t.transform(new StAXSource(xsr), new StreamResult(file));
        }
    }

}
于 2010-12-04T12:43:21.903 に答える
4

Stax は低レベルのアクセス API であり、コンテンツに再帰的にアクセスするルックアップやメソッドはありません。しかし、あなたは実際に何をしようとしていますか?なぜスタックスを検討しているのですか?

XPath でうまく機能するツリー モデル (DOM、XOM、JDOM、Dom4j) を使用する以外に、データを処理する場合の最良の選択は、通常、JAXB のようなデータ バインディング ライブラリです。これを使用すると、Stax または SAX リーダーを渡し、xml データを Java Bean にバインドするように要求できます。xml プロセスの Java オブジェクトをいじる必要はありません。これは多くの場合、より便利であり、通常はかなりのパフォーマンスです。より大きなファイルでの唯一のトリックは、一度にすべてをバインドするのではなく、各サブツリーをバインドすることです(この場合、一度に1つの「ステートメント」)。これは、Stax XmlStreamReader を反復処理してから、JAXB を使用してバインドすることによって最も簡単に実行できます。

于 2010-12-04T05:24:46.653 に答える
1

私はグーグルで検索してきましたが、これは非常に難しいようです。

私のxmlを考えると、次のほうが簡単かもしれないと思います:

StringBuilder buffer = new StringBuilder();
for each line in file {
   buffer.append(line)
   if(line.equals(STMT_END_TAG)){
      parse(buffer.toString())
      buffer.delete(0,buffer.length)
   }
 }

 private void parse(String statement){
    //saxParser.parse( new InputSource( new StringReader( xmlText ) );
    // do stuff
    // save string
 }
于 2010-12-04T04:12:02.880 に答える
0

これにxpathを使用しないのはなぜですか?

すべての「ステートメント」ノードを取得するには、かなり単純な xpath を使用できます。

そのようです:

//statement

編集 #1: 可能であれば、dom4jを見てください。String を読み取って、すべての「statement」ノードをかなり簡単に取得できます。

編集 #2: dom4j を使用すると、次のようになります: (クックブックから)

String text = "your xml here";
Document document = DocumentHelper.parseText(text);

public void bar(Document document) {
   List list = document.selectNodes( "//statement" );
   // loop through node data
}
于 2010-12-04T05:00:34.610 に答える