2010-11-24 3 views
4

StAX를 사용하려고합니다. (이미 싫어합니다 ....)
사용하는 유일한 방법은 if-else 조건 연속입니다.
가장 중요한 것은 미리 구문 분석되는 XML 문서의 구조를 미리 알지 못하는 한 요소를 자식과 연관시킬 수있는 방법이 없다는 것입니다. 정확합니까? 나는 다음과 같은 시도
: 나는 문자열이 XML을java StAX를 사용하여 일반 요소로 자식 요소를 가져옵니다.

<ns1:Root xmlns:ns1=\"http://rootNameSpace.com/\"> 
<ns1:A/> 
<ns1:B> 
     <Book xmlns=\"http://www.myNameSpace.com\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"> 
      <Data> 
       <Author>John</Author> 
       <Edition>1</Edition> 
       <PubHouse>Small Publishing House</PubHouse> 
       <Price>37.8</Price> 
      </Data> 
     </Book> 
</ns1:B> 
</ns1:Root> 

내가 책 요소를 얻을 경우 StAX를 사용하고자하지만 난 단지 모든 구조를 하드 코딩 코드를 작성할 수 있습니다 보인다.
즉, XMLEventReader를 사용하고 나서 을 예약하면 데이터, 제작자 등을 위해 루핑을 시작하십시오.
여기에 일반적인 해결책이 있습니까?
다음과 같이 arround를 얻으려고 시도했습니다. String에서 XMLEventReader로 이동하여 String으로 돌아가려고했지만 원래 사용했던 정확한 String 표현을 얻을 수 없습니다 (네임 스페이스는 대괄호, 여분의 콜론 등).

<?xml version="1.0" encoding='UTF-8' standalone='no'?><['http://rootNameSpace.com/']:ns1:Root xmlns:ns1='http://rootNameSpace.com/'><['http://rootNameSpace.com/']:ns1:A></ns1:A><['http://rootNameSpace.com/']:ns1:B><['http://www.myNameSpace.com']::Book xmlns:='http://www.myNameSpace.com' xmlns:xsd='http://www.w3.org/2001/XMLSchema' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'><['http://www.myNameSpace.com']::Data><['http://www.myNameSpace.com']::Author>John</Author><['http://www.myNameSpace.com']::Edition>1</Edition><['http://www.myNameSpace.com']::PubHouse>Small Publishing House</PubHouse><['http://www.myNameSpace.com']::Price>37.8</Price></Data></Book></ns1:B></ns1:Root> 

이 경우는 유일한 솔루션입니다 StAX를하거나 DOM을 통해 해결 될 수 :

StringBuilder xml = new StringBuilder(); 
XMLInputFactory inputFactory = XMLInputFactory.newInstance(); 
String msg = "<ns1:Root xmlns:ns1=\"http://rootNameSpace.com/\"><ns1:A/><ns1:B><Book xmlns=\"http://www.myNameSpace.com\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"><Data><Author>John</Author><Edition>1</Edition><PubHouse>Small Publishing House</PubHouse><Price>37.8</Price></Data></Book></ns1:B></ns1:Root>"; 
InputStream input = new ByteArrayInputStream(msg.getBytes("UTF-8")); 
XMLEventReader xmlEventReader = inputFactory.createXMLEventReader(input); 
while (xmlEventReader.hasNext()) 
{ 

    XMLEvent event = xmlEventReader.nextEvent(); 
    StringWriter sw = new StringWriter(); 
    event.writeAsEncodedUnicode(sw); 
    xml.append(sw); 

} 
System.out.println(xml); 

나는 다음과 같은거야?

답변

5

난 정말 당신이 뭘하려는 건지 이해하지 않지만, 당신이 START_ELEMENT 이벤트를 일으키는 원인이되는 태그의 로컬 이름을 원하는 경우, 당신은 이런 식으로 작업을 수행 할 수 있습니다

if (event.getEventType() == START_ELEMENT) { 
    QName qname = event.asStartElement().getName() 
    System.out.println("Start of element " + qname.getLocalPart()); 
} 

마찬가지로, asEndElement , asCharacters 등은 다른 유형의 노드에 대한 액세스를 제공합니다.

개인적으로 대부분의 상황에서 XMLStreamReader이 나를 위해 더 편리하다는 것을 알지만, 유스 케이스와 개인적인 취향에 달려 있다고 생각합니다. 프로 팁은 스키마가 엄격할수록 데이터가 StAX와 더 쉽게 파싱된다는 것입니다.

JAX-B에서 자동 XML 데이터 바인딩을 확인하고자 할 수도 있습니다.

편집 :은 여기 영업 이익의 XML에 대한 순진 재귀 하강 StAX를 파서이다 :이 같은

@Test 
public void recursiveDescentStaxParser() throws XMLStreamException, 
     FactoryConfigurationError 
{ 
    String msg = "<ns1:Root xmlns:ns1=\"http://rootNameSpace.com/\"><ns1:A/><ns1:B><Book xmlns=\"http://www.myNameSpace.com\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"><Data><Author>John</Author><Edition>1</Edition><PubHouse>Small Publishing House</PubHouse><Price>37.8</Price></Data></Book></ns1:B></ns1:Root>"; 
    XMLStreamReader reader = XMLInputFactory.newFactory() 
      .createXMLStreamReader(new StringReader(msg)); 

    reader.nextTag(); 
    readRoot(reader); 

} 

private void readRoot(XMLStreamReader reader) throws XMLStreamException 
{ 
    while (reader.nextTag() == XMLEvent.START_ELEMENT) 
    { 
     QName name = reader.getName(); 
     if ("B".equals(name.getLocalPart())) 
      readBooks(reader); 
     else 
      reader.nextTag(); // Empty <A> 

    } 
} 

private void readBooks(XMLStreamReader reader) throws XMLStreamException 
{ 
    while (reader.nextTag() == XMLEvent.START_ELEMENT) 
    { 
     QName name = reader.getName(); 
     if (!"Book".equals(name.getLocalPart())) 
      throw new XMLStreamException(name.toString()); 
     reader.nextTag(); // Jump to <Data> 
     readBook(reader); 
     reader.nextTag(); // Jump to </B> 
    } 
} 

private void readBook(XMLStreamReader reader) throws XMLStreamException 
{ 
    reader.nextTag(); // Skip to <Author> 
    System.out.println("Author: " + reader.getElementText()); 
    reader.nextTag(); // Skip to <Edition> 
    System.out.println("Edition: " + reader.getElementText()); 
    reader.nextTag(); // Skip to <PubHouse> 
    System.out.println("Publisher: " + reader.getElementText()); 
    reader.nextTag(); // Skip to <Price> 
    System.out.println("Price: " + reader.getElementText()); 
    reader.nextTag(); // Skip to </Book> 

} 

쓰기 물건은 읽기 전용에 대한 이유에 코드가 훨씬 쉽게하지 않지만 또한 스택 오류가 팝업 때 추적합니다.

+0

@gustafc : 게시 한 코드로 요소가 시작된다는 것을 알았습니다.이 요소의 모든 자식을 어떻게 가져올 수 있습니까? DOM은 사소한 것입니다. StAX에서 어떻게합니까? – Cratylus

+0

글쎄, 모든 이벤트를 요소의 "내부"로 가져 오려면 START_ELEMENT 이벤트보다 하나 더 END_ELEMENT를 찾을 때까지 이벤트를 읽어야합니다. 그러나 그것은 끔찍한 DOMish 방식입니다. 실제로하고 싶은 것은 반복적 인 하향 파서입니다. 각 파서는 각 요소를 읽고이를 즉시 일부 도메인 객체로 변환합니다. 진절머리 나는 설명에 대해 유감스럽게 생각하지만 StAX를 효과적으로 사용하는 것을 배우는 것은 실제로 대부분 DOM 중독을 유발하는 문제입니다. – gustafc

+0

@gustafc : 나는 상상했다. "재귀 적 파서 파서"라고 말하면 StAX를 사용하지 않는다는 뜻인가요? StAX는 "해킹"을 사용하지 않고 이것을 제공하지 않습니까? – Cratylus

1

잘못된 도구를 선택했을 수도 있습니다. Stax는 큰 콘텐츠를 효율적으로 처리하는 데 유용한 훌륭한 API입니다. 그러나 편의성이 효율성보다 더 중요하다면 네, 아마도 DOM 모델 (예 : DOM이 아니거나 XOM이 더 좋음) 또는 데이터 바인딩 (JAXB 또는 XStream)을 고려해야합니다. 특히 SAX와 같은 Stax는 스트림 기반이므로 현재 이벤트 나 토큰이 무엇인지 만 볼 수 있습니다. 아이들이나 부모에게는 접근 할 수있는 방법이 없기 때문에 접근 할 수 없습니다. 현재 스트림 위치를 고려할 때 반드시 필요한 것은 아니기 때문입니다.

성능이나 메모리 사용에 문제가있는 경우 JAXB (일반적으로 DOM과 같은 트리 모델보다 효율적) 또는 StaxMate을 고려할 수 있습니다.StaxMate는 Stax보다 고성능, 메모리 사용량이 적으며 사용하기에 더 편리합니다. 여전히 문서 순서로 요소를 반복해야하지만, 커서 접근 방식은 부모와 자식 조회로 자연스럽게 매핑됩니다. 따라서 귀하의 경우에 효과가있을 수 있습니다.