2012-07-02 2 views
0

XML 파일을 태그에 상관없이 파싱하고 모든 나뭇잎 (텍스트 요소 만)의 텍스트를 읽어야합니다. 나는 StAX를 사용하고 있지만, 엘리먼트가 텍스트 일 ​​뿐이라는 것을 미리 알 수있는 방법이 없다. 그래서 getElementText는 엘리먼트를 남겨 두지 않는 예외를 던진다. 그래서 난 단지 태그 요소를 필터링 필터를 사용하기로 결정하고, 반복 처리는이 방법으로 문서를 던져 :StAX를 사용하여 모든 텍스트 요소를 읽으십시오

InputStream in = null; 
    try { 
     in = new FileInputStream("file.xml"); 
     DatiEstratti de = DatiEstratti.getInstance(); 

     // Processamento ad eventi 
     XMLInputFactory factory = (XMLInputFactory) XMLInputFactory.newInstance(); 

     XMLEventReader eventReader = factory.createXMLEventReader(in); 
     // usa il filtro per filtrare solo i tag element 
     eventReader = factory.createFilteredReader(eventReader, new ElementOnlyFilter()); 

     while (eventReader.hasNext()) { 

      XMLEvent event = eventReader.nextEvent(); 

      if (event.getEventType() == XMLStreamConstants.START_ELEMENT) { 
       StartElement startElement = event.asStartElement(); 

       XMLEvent peekEvent = eventReader.peek(); 
       if(peekEvent.isEndElement()){ 
        // questa è la prima volta che viene fatto un pop 
        // quindi è una foglia. 
        // recupera il dato. 
        String value = eventReader.getElementText(); 

        logger.info("dato : " + value); 
       } 


       String nome = startElement.getName().getLocalPart(); 
       String prefix = startElement.getName().getPrefix(); 
       if (prefix != null) { 
        nome = prefix + ":" + nome; 
       } 
       de.push(nome); 
       logger.info("push : " + de.stampaPercorso()); 



      } else if ((event.getEventType() == XMLStreamConstants.END_ELEMENT)) { 

       de.pop(); 
       logger.info("pop : " + de.stampaPercorso()); 
       if (0 > de.nLivelliPercorso()) { 
        break; 
       } 
      } 
      //handle more event types here... 
     } 

... 필터는 다음과 같습니다

public class ElementOnlyFilter implements EventFilter, StreamFilter { 

/* implementation of EventFilter interface */ 
@Override 
public boolean accept(XMLEvent event) { 
    return acceptInternal(event.getEventType()); 
} 

/* implementation of StreamFilter interface */ 
@Override 
public boolean accept(XMLStreamReader reader) { 
    return acceptInternal(reader.getEventType()); 
} 

/* internal utility method */ 
private boolean acceptInternal(int eventType) { 
    return eventType == XMLStreamConstants.START_ELEMENT 
      || eventType == XMLStreamConstants.END_ELEMENT; 
} 

} 

문제가 있다는 것입니다 I 휴가가 발견되면 다음 예외가 있습니다.

javax.xml.stream.XMLStreamException: ParseError at [row,col]:[3,42] 
Message: parser must be on START_ELEMENT to read next text 
    at com.sun.xml.internal.stream.XMLEventReaderImpl.getElementText(XMLEventReaderImpl.java:114) 
    at javax.xml.stream.util.EventReaderDelegate.getElementText(EventReaderDelegate.java:88) 
    at xmlparser.XmlParser.main(XmlParser.java:63) 

나는 궁금합니다. 이 코드에 결함이 있습니까? peek()은 독자를 변경하지 않으므로 getElementText()는 시작 요소에 의해 호출되어야한다고 생각했습니다. 다른 목표를 달성 할 수있는 방법이 있습니까?

답변

4

첫 번째로 시작 및 끝 요소 이벤트 만 포함하도록 필터링하면 리프 노드 안에 포함 된 텍스트가 전혀 표시되지 않습니다. 나는 다음과 같이 필터링되지 않은 스트림과 다른 접근 방식을 사용 :

XMLEventReader eventReader = factory.createXMLEventReader(in); 
StringBuilder content = null; 
while(eventReader.hasNext()) { 
    XMLEvent event = eventReader.nextEvent(); 
    if(event.isStartElement()) { 
    // other start element processing here 
    content = new StringBuilder(); 
    } else if(event.isEndElement()) { 
    if(content != null) { 
     // this was a leaf element 
     String leafText = content.toString(); 
     // do something with the leaf node 
    } else { 
     // not a leaf 
    } 
    // in all cases, discard content 
    content = null; 
    } else if(event.isCharacters()) { 
    if(content != null) { 
     content.append(event.asCharacters().getData()); 
    } 
    } 
    // other event types here 
} 

트릭 최종 요소 섹션의 끝 부분에있는 content = null입니다 - content은 다음 null이 아닌 경우 if(event.isEndElement()) 블록 항목에 이 태그와 대응하는 시작 태그 사이에 중간 요소 이벤트가 없다는 것을 알았습니다. 즉, 해당 노드는 리프 노드입니다.

+0

고마워, 그건 내 문제를 해결! – maxqua72

관련 문제