3

Java: 1.6
ウッドストック: 4.1.4

解析中にxmlファイルの一部をスキップしたいだけです。その単純な xml を見てみましょう。

<family>
    <mom>
        <data height="160"/>
    </mom>
    <dad>
        <data height="175"/>
    </dad>
</family>

お父さんの要素をスキップしたいだけです。したがって、以下に示すように skipElement メソッドを使用することをお勧めします。

FileInputStream fis = ...;
XMLStreamReader2 xmlsr = (XMLStreamReader2) xmlif.createXMLStreamReader(fis);

String currentElementName = null;
while(xmlsr.hasNext()){

    int eventType = xmlsr.next();

    switch(eventType){

        case (XMLEvent2.START_ELEMENT):
            currentElementName = xmlsr.getName().toString();

            if("dad".equals(currentElementName) == true){
                logger.info("isStartElement: " + xmlsr.isStartElement());
                logger.info("Element BEGIN: " + currentElementName);
                xmlsr.skipElement();
            }

                    ...
    }
}

要素 dad の開始を見つけてスキップします。ただし、例外がスローされるため、それほど高速ではありません。これは出力です:

isStartElement: true
Element BEGIN: dad
Exception in thread "main" java.lang.IllegalStateException: Current state not START_ELEMENT

それは期待したものではありません。メソッド skipElement が START_ELEMENT 状態で実行されるため、これは非常に予想外です。何が起こっているのかわかりません。多分あなたはもっと知っています:)。だから私を助けてください。

よろしく
お願いします

4

4 に答える 4

2

ライブラリパスにwoodstox-core-lgpl-4.1.4.jar、stax2-api-3.1.1.jarを使用して、Java 1.6(jdk1.6.0_30)でこれを試しました。私のJavaファイルはこれです:

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;

import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;

import org.codehaus.stax2.XMLStreamReader2;
import org.codehaus.stax2.evt.XMLEvent2;

public class Skip {

    public static void main(String[] args) throws FileNotFoundException,
            XMLStreamException {
        System.setProperty("javax.xml.stream.XMLInputFactory",
                "com.ctc.wstx.stax.WstxInputFactory");
        System.setProperty("javax.xml.stream.XMLOutputFactory",
                "com.ctc.wstx.stax.WstxOutputFactory");
        System.setProperty("javax.xml.stream.XMLEventFactory",
                "com.ctc.wstx.stax.WstxEventFactory");

        FileInputStream fis = new FileInputStream(new File("family.xml"));
        XMLInputFactory xmlif = XMLInputFactory.newFactory();
        XMLStreamReader2 xmlsr = (XMLStreamReader2) xmlif
                .createXMLStreamReader(fis);

        String currentElementName = null;
        while (xmlsr.hasNext()) {

            int eventType = xmlsr.next();

            switch (eventType) {

            case (XMLEvent2.START_ELEMENT):
                currentElementName = xmlsr.getName().toString();

                if ("dad".equals(currentElementName) == true) {
                    System.out.println("isStartElement: "
                            + xmlsr.isStartElement());
                    System.out.println("Element BEGIN: " + currentElementName);
                    xmlsr.skipElement();
                }
                else {
                    System.out.println(currentElementName);
                }

            }
        }
    }
}

魅力のように機能します。出力は

family
mom
data
isStartElement: true
Element BEGIN: dad
于 2013-01-14T21:42:24.053 に答える
2

IllegalStateException が発生した理由がわかりました。非常に役立つのは、flupの答えでした。どうもありがとう。
Blaiseからの回答も読む価値があります。

しかし、問題の核心に到達します。問題は skipElement() メソッド自体ではありませんでした。この問題は、属性の読み取りに使用されるメソッドが原因で発生しました。私の質問には 3 つのドット (...) があります。それでは、何があったか見てみましょう。

switch(eventType){

case (XMLEvent2.START_ELEMENT):
    currentElementName = xmlsr.getName().toString();
    logger.info("currentElementName: " + currentElementName);


    if("dad".equals(currentElementName) == true){
        logger.info("isStartElement: " + xmlsr.isStartElement());
        logger.info("Element BEGIN: " + currentElementName);
        xmlsr.skipElement();
    }


    case (XMLEvent2.ATTRIBUTE):
        int attributeCount = xmlsr.getAttributeCount(); 
        ...
        break;


}

重要なこと。START_ELEMENT の break ステートメントはありません。したがって、START_ELEMENT イベントが発生するたびに、イベント ATTRIBUTE のコードも実行されます。メソッド getAttributeCount()、getAttributeValue() などは START_ELEMENT と ATTRIBUTE の両方に対して実行できるため、Java Docs によると問題ないようです。

ただし、skipElement() メソッドを呼び出した後、イベント START_ELEMENT は END_ELEMENT に変更されます。そのため、メソッド getAttributeCount() の呼び出しは許可されていません。この呼び出しが、IllegalStateException がスローされる理由です。

その例外を回避する最も簡単な方法は、skipElement() メソッドを呼び出した後に break ステートメントを呼び出すことです。その場合、属性を取得するためのコードは実行されないため、例外はスローされません。

        if("dad".equals(currentElementName) == true){
            logger.info("isStartElement: " + xmlsr.isStartElement());
            logger.info("Element BEGIN: " + currentElementName);
            xmlsr.skipElement();
            break;                  //the cure for IllegalStateException
        }

多くのコードが隠されているため、元の質問に答える機会を与えなかったことをお詫びします。

于 2013-01-15T15:07:20.863 に答える
2

Woodstox は StAX (JSR-173) 準拠のパーサーであるため、StAX を使用StreamFilterして特定の要素に対応するイベントを除外できます。フィルタリング ロジックをアプリケーション ロジックから分離しておくことができるので、私はこのアプローチを好みます。

デモ

import javax.xml.stream.*;
import javax.xml.transform.stream.StreamSource;

public class Demo {

    public static void main(String[] args) throws Exception {
        XMLInputFactory xif = XMLInputFactory.newFactory();
        StreamSource xml = new StreamSource("src/forum14326598/input.xml");
        XMLStreamReader xsr = xif.createXMLStreamReader(xml);
        xsr = xif.createFilteredReader(xsr, new StreamFilter() {

            private boolean accept = true;

            @Override
            public boolean accept(XMLStreamReader reader) {
                if((reader.isStartElement() || reader.isEndElement()) && "dad".equals(reader.getLocalName())) {
                    accept = !accept;
                    return false;
                } else {
                    return accept;
                }
            }

        });

        while(xsr.hasNext()) {
            if(xsr.isStartElement()) {
                System.out.println("start: " + xsr.getLocalName());
            } else if(xsr.isCharacters()) {
                if(xsr.getText().trim().length() > 0) {
                    System.out.println("chars: " + xsr.getText());
                }
            } else if(xsr.isEndElement()) {
                System.out.println("end: " + xsr.getLocalName());
            }
            xsr.next();
        }
    }

}

出力

start: family
start: mom
start: data
end: data
end: mom
end: family
于 2013-01-14T21:56:56.173 に答える
0

メソッドxmlsr.skipElement()は、XMLEvent2.START_ELEMENTイベントを消費する必要があるようです。そして、すでにそれを消費しているので(xmlsr.next())、そのメソッドはエラーをスローします。

于 2013-01-14T21:13:40.530 に答える