2013-01-14 33 views
3

的Java的一部分:1.6
Woodstox:4.1.4woodstox跳過XML

我只是想跳過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(); 
      } 

        ... 
    } 
} 

我們只找到元素爸爸的開始,並跳過它。 但不是那麼快,因爲異常將被拋出。這是輸出:

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

這不是預期的結果。這確實是非常意外的,因爲方法skipElement在START_ELEMENT狀態下執行。我不知道發生了什麼,也許你知道更多:)。 所以請幫助我。

在此先感謝
休伯特

+0

'== true'很明顯,但多餘。 –

回答

2

我已經找到了原因,爲什麼我得到的IllegalStateException異常。非常有用的是flup的答案。非常感謝。
也值得閱讀由Blaise給出的答案。

但是越來越重要。 問題不是skipElement()方法本身。問題是由於用於讀取屬性的方法引起的。在我的問題中有三個點(...)。那麼讓我們看看有什麼:

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沒有中斷聲明。所以每次發生START_ELEMENT事件時,ATTRIBUTE事件的代碼也會被執行。 根據Java文檔,這看起來不錯,可以爲START_ELEMENT和ATTRIBUTE執行getAttributeCount(),getAttributeValue()等方法。

但是在調用方法skipElement()之後,事件START_ELEMENT變爲END_ELEMENT。所以調用方法getAttributeCount()是不允許的。這個調用是拋出IllegalStateException的原因。

避免該異常的最簡單方法是調用skipElement()方法後調用break語句。在這種情況下,獲取屬性的代碼將不會被執行,因此Exception不會被拋出。

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

對不起,我給你沒有機會回答我原來的問題,因爲隱藏了很多代碼。

0

它看起來像法xmlsr.skipElement()是必須使用的XMLEvent2.START_ELEMENT事件之一。而且由於您已經使用了它(xmlsr.next()),該方法會引發錯誤。

2

我在java 1.6(jdk1.6.0_30)中用woodstox-core-lgpl-4.1.4.jar,stax2-api-3.1.1.jar在庫路徑中試過了。 我的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 
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