3

彼ら。

それがバグなのか、それとも私自身の教育不足なのかを理解するためにかなりの時間を費やしました。基本的に、私は特定の要素に反応し、JavaStAXAPIを使用してTransformerでその内容を読み取ろうとしています。

XMLがきれいにフォーマットされているか、要素間にスペースがある場合は、すべてが機能します。ただし、要素間に空白文字がないXMLを検出するとすぐに、ひどく壊れます。

問題を説明するためのコードとその出力があります。

3つのサンプルXMLがあり、最初の2つは2つの異なるブレークシナリオを示し、最後の1つは適切な処理を示しています。

  • スペースのない最初のシナリオでは、いくつかの要素をスキップします。以下の例では、1つの「ノード」要素を除くすべてをスキップします。実際のシナリオでは、代わりに他のすべてのノードをスキップします。おそらく、ノードのコンテンツが豊富なためです。

  • 2番目のシナリオでは、ノード要素間にのみスペースを追加しました。ご覧のとおり、ドキュメントの終わりを適切に処理できません。

  • 最後のシナリオでは、最後のノードとルート要素を閉じる間にスペースを追加しました。処理は希望どおりに行われました。

私の実際のシナリオでは、区切り文字のない単一行のXMLを期待しているので、シナリオ1が正しく機能する必要があります。また、要素間にスペースを追加するなど、XMLに有効な変更を加えても、処理が中断されないことを知って幸せです。シナリオ2のように。

助けてください!!!

シングルクラスアプリケーションテストの完全なコード。StAXTest:

package test;

import java.io.StringReader;
import java.io.StringWriter;

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 StAXTest {
    private final static String XML1 = "<root><node></node><node></node></root>";
    private final static String XML2 = "<root><node></node> <node></node></root>";
    private final static String XML3 = "<root><node></node> <node></node> </root>";

    public static void main(String[] args) throws Exception {
        processXML(XML1);
        processXML(XML2);
        processXML(XML3);
    }

    private static void processXML(String xml) {
        try {
            System.out.println("XML Input:\n" + xml + "\nProcessing:");

            XMLInputFactory xif = XMLInputFactory.newInstance();
            XMLStreamReader reader = xif.createXMLStreamReader(new StringReader(xml));
            TransformerFactory tf = TransformerFactory.newInstance();

            int nodeCount = 0;

            while (reader.nextTag() == XMLStreamConstants.START_ELEMENT) {
                String localName = reader.getLocalName();
                if (localName.equals("node")) {
                    Transformer t = tf.newTransformer();
                    StringWriter st = new StringWriter();
                    t.transform(new StAXSource(reader), new StreamResult(st));
                    String xmlNode = st.toString();
                    System.out.println(nodeCount + ": " + xmlNode);
                    nodeCount++;
                }
            }
        } catch (Throwable t) {
            t.printStackTrace(System.out);
        }
        System.out.println("------------------------------------------------");
    }
}

3つのシナリオすべてを含むアプリケーション出力。最初のシナリオでは、変換されたXML部分に2つではなく1つのノードが含まれていることに注意してください。したがって、2番目のノードは完全に「変換で失われます」。

XML Input:
<root><node></node><node></node></root>
Processing:
0: <?xml version="1.0" encoding="UTF-8"?><node/>
------------------------------------------------
XML Input:
<root><node></node> <node></node></root>
Processing:
0: <?xml version="1.0" encoding="UTF-8"?><node/>
1: <?xml version="1.0" encoding="UTF-8"?><node/>
javax.xml.stream.XMLStreamException: ParseError at [row,col]:[-1,-1]
Message: found: END_DOCUMENT, expected START_ELEMENT or END_ELEMENT
    at com.sun.org.apache.xerces.internal.impl.XMLStreamReaderImpl.nextTag(XMLStreamReaderImpl.java:1247)
    at com.newedge.test.StAXTest.processXML(StAXTest.java:35)
    at com.newedge.test.StAXTest.main(StAXTest.java:21)
------------------------------------------------
XML Input:
<root><node></node> <node></node> </root>
Processing:
0: <?xml version="1.0" encoding="UTF-8"?><node/>
1: <?xml version="1.0" encoding="UTF-8"?><node/>
------------------------------------------------
4

2 に答える 2

8

問題は、transformメソッドを使用した後XMLStreamReader、処理する次のXMLイベント(つまり、2番目の<node>開始タグまたは</root>終了タグ)を指したままになることです。ただし、ループnextTag()の先頭で呼び出すとwhile、リーダーはさらに1つのイベントで進みます。これにより、このイベントがスキップされます。

</node>終了タグの後に空白がある例では、スキップされたのは空白文字データイベントでした。その他の場合、XMLの開始要素または終了要素のイベントがスキップされていたため、予期しない結果が発生していました。

START_ELEMENTトランスフォーマーを呼び出した後、リーダーの現在のeventTypeがまたはであるかどうかを確認する必要がありますEND_ELEMENT。もしそうなら、トランスフォーマーはすでにリーダーを進めているので、それ以上進めないでください。eventTypeが別のものである場合、またはトランスフォーマーを呼び出さなかった場合は、呼び出しnextTag()てリーダーを次のタグに進めます。

while私はあなたのループを次のものに置き換えました:

        int eventType = reader.nextTag();
        while (eventType == XMLStreamConstants.START_ELEMENT) {
            String localName = reader.getLocalName();
            if (localName.equals("node")) {
                Transformer t = tf.newTransformer();
                StringWriter st = new StringWriter();
                t.transform(new StAXSource(reader), new StreamResult(st));
                String xmlNode = st.toString();
                System.out.println(nodeCount + ": " + xmlNode);
                nodeCount++;
                eventType = reader.getEventType();
                if (eventType != XMLStreamConstants.START_ELEMENT && eventType != XMLStreamConstants.END_ELEMENT) {
                    eventType = reader.nextTag();
                }
            } else {
                eventType = reader.nextTag();
            }

次にコードを実行すると、次の出力が得られました。

XML Input:
<root><node></node><node></node></root>
Processing:
0: <?xml version="1.0" encoding="UTF-8"?><node/>
1: <?xml version="1.0" encoding="UTF-8"?><node/>
------------------------------------------------
XML Input:
<root><node></node> <node></node></root>
Processing:
0: <?xml version="1.0" encoding="UTF-8"?><node/>
1: <?xml version="1.0" encoding="UTF-8"?><node/>
------------------------------------------------
XML Input:
<root><node></node> <node></node> </root>
Processing:
0: <?xml version="1.0" encoding="UTF-8"?><node/>
1: <?xml version="1.0" encoding="UTF-8"?><node/>
------------------------------------------------
于 2013-01-25T20:37:08.940 に答える
1

コードに感謝しますが、これでもエラーが発生しました-小さなコンテンツを微調整して、現在は機能しています

while(eventType == XMLStreamConstants.START_ELEMENT)
{
     String localName = reader.getLocalName();
     System.out.println(localName);

     if(localName == null)
     {
         eventType = reader.nextTag();
     }


    // Rest Program is same

}
于 2013-08-16T10:20:54.233 に答える