2012-12-19 3 views
5

큰 복잡한 XML을 구문 분석하고 플랫 파일에 쓸 필요가 있습니다. 몇 가지 조언을 해줄 수 있습니까?큰 복잡한 XML을 구문 분석하는 방법

파일 크기 : 5백메가바이트 는 기록 수 : 100K XML 구조 :

<Msg> 

    <MsgHeader> 
     <!--Some of the fields in the MsgHeader need to be map to a java object--> 
    </MsgHeader> 

    <GroupA> 
     <GroupAHeader/> 
     <!--Some of the fields in the GroupAHeader need to be map to a java object--> 
     <GroupAMsg/> 
     <!--50K records--> 
     <GroupAMsg/> 
     <GroupAMsg/> 
     <GroupAMsg/> 
    </GroupA> 

    <GroupB> 
     <GroupBHeader/> 
     <GroupBMsg/> 
     <!--50K records--> 
     <GroupBMsg/> 
     <GroupBMsg/> 
     <GroupBMsg/> 
    </GroupB> 

</Msg> 
+4

특정 언어 당신은 '이 : 그건 당신이 정말

다음 예는 당신의 구조 xml 파일에 읽고 GroupBMsg-태그 내의 모든 텍스트를 출력 필요 뭔가 있는지 확실하지 않습니다 다시 사용할거야? –

+0

파일의 구조를 확인해야합니까, 아니면 sé 당 유효하다고 생각할 수 있습니까? – Thilo

+0

JAXB/Spring Batch를 사용하고 있습니다. 많은 게시물을 읽었지만 xml보다 효과적으로 처리하는 방법에 대해서는 아직 모릅니다. – Weber

답변

0

나는 그런 큰 파일 크기 처리하지만, 문제를 고려하지 않은, 당신은 을 분석하고 쓰고 싶어하기 때문에 플랫 파일 (this might help)에 쓰기 위해 XML Pull Parsing과 스마트 코드 조합을 추측하고 있습니다. 자바 힙을 고갈시키고 싶지 않기 때문입니다. XML Pull Parsing을 사용하여 자습서 및 샘플 코드에 대한 빠른 Google 검색을 수행 할 수 있습니다.

+0

예, JAXB/Spring Batch가 선호되는 옵션이지만 복잡한 xml보다 효과적으로 구문 분석하는 방법에 대해서는 잘 모르는 경우가 있습니다. 나는 큰 xml 파싱을하는 초보자이다. 모든 의견을 주시면 감사하겠습니다. – Weber

0

마지막으로, 사용자 지정된 StaxEventItemReader를 구현합니다.

  1. 구성 fragmentRootElementName

  2. 구성 MyStaxEventItemReader.doRead 내 자신 manualHandleElement

    <property name="manualHandleElement"> 
    <list> 
        <map> 
         <entry> 
          <key><value>startElementName</value></key> 
          <value>GroupA</value> 
         </entry> 
         <entry> 
          <key><value>endElementName</value></key> 
          <value>GroupAHeader</value> 
         </entry> 
         <entry> 
          <key><value>elementNameList</value></key> 
           <list> 
             <value>/GroupAHeader/Info1</value> 
             <value>/GroupAHeader/Info2</value> 
           </list> 
         </entry> 
        </map> 
    </list> 
    

  3. 추가 다음 조각()

    while(true){ 
    if(reader.peek() != null && reader.peek().isStartElement()){ 
        pathList.add("/"+((StartElement) reader.peek()).getName().getLocalPart()); 
        reader.nextEvent(); 
        continue; 
    } 
    if(reader.peek() != null && reader.peek().isEndElement()){ 
        pathList.remove("/"+((EndElement) reader.peek()).getName().getLocalPart()); 
        if(isManualHandleEndElement(((EndElement) reader.peek()).getName().getLocalPart())){ 
         pathList.clear(); 
         reader.nextEvent(); 
         break; 
        } 
        reader.nextEvent(); 
        continue; 
    } 
    if(reader.peek() != null && reader.peek().isCharacters()){ 
        CharacterEvent charEvent = (CharacterEvent)reader.nextEvent(); 
        String currentPath = getCurrentPath(pathList); 
        String startElementName = (String)currentManualHandleStartElement.get(MANUAL_HANDLE_START_ELEMENT_NAME); 
        for(Object s : (List)currentManualHandleStartElement.get(MANUAL_HANDLE_ELEMENT_NAME_LIST)){ 
         if(("/"+startElementName+s).equals(currentPath)){ 
          map.put(getCurrentPath(pathList), charEvent.getData()); 
          break; 
         } 
        } 
        continue; 
    } 
    
    reader.nextEvent(); 
    

    }

1

같은 일부 ETL 툴을 사용해 보시기 바랍니다, 나는 더 구체적보다 약간을 운영하고 내 자신의 STAX 이벤트 항목 판독기 구현을 작성했습니다 이전에 언급 한. 기본적으로 요소를 맵에 채운 다음 ItemProcessor에 전달합니다. 거기에서 "GatheredElement"의 단일 객체 (CompositeItemProcessor 참조)로 변환 할 수 있습니다. StaxEventItemReader에서 약간의 복사/붙여 넣기를하는 것에 대해 사과드립니다.하지만 피할 수는 없다고 생각합니다.

여기에서 원하는 OXM 마샬 러를 자유롭게 사용할 수 있습니다. JAXB도 사용합니다.

public class ElementGatheringStaxEventItemReader<T> extends StaxEventItemReader<T> { 
    private Map<String, String> gatheredElements; 
    private Set<String> elementsToGather; 
    ... 
    @Override 
    protected boolean moveCursorToNextFragment(XMLEventReader reader) throws NonTransientResourceException { 
     try { 
      while (true) { 
       while (reader.peek() != null && !reader.peek().isStartElement()) { 
        reader.nextEvent(); 
       } 
       if (reader.peek() == null) { 
        return false; 
       } 
       QName startElementName = ((StartElement) reader.peek()).getName(); 
       if(elementsToGather.contains(startElementName.getLocalPart())) { 
        reader.nextEvent(); // move past the actual start element 
        XMLEvent dataEvent = reader.nextEvent(); 
        gatheredElements.put(startElementName.getLocalPart(), dataEvent.asCharacters().getData()); 
        continue; 
       } 
       if (startElementName.getLocalPart().equals(fragmentRootElementName)) { 
        if (fragmentRootElementNameSpace == null || startElementName.getNamespaceURI().equals(fragmentRootElementNameSpace)) { 
         return true; 
        } 
       } 
       reader.nextEvent(); 

      } 
     } catch (XMLStreamException e) { 
      throw new NonTransientResourceException("Error while reading from event reader", e); 
     } 
    } 

    @SuppressWarnings("unchecked") 
    @Override 
    protected T doRead() throws Exception { 
     T item = super.doRead(); 
     if(null == item) 
      return null; 
     T result = (T) new GatheredElementItem<T>(item, new  HashedMap(gatheredElements)); 
     if(log.isDebugEnabled()) 
      log.debug("Read GatheredElementItem: " + result); 
     return result; 
    } 

수집 된 요소 클래스

아주 기본입니다 : 당신이 옆 JAXB/스프링 배치를 솔루션을 받아 들일 경우, SAX 파서를 보라 할 수 있습니다

public class GatheredElementItem<T> { 
    private final T item; 
    private final Map<String, String> gatheredElements; 
    ... 
} 
0

.

이것은 이벤트 지향적 인 XML 파일 구문 분석 방법으로, 구문 분석 중에 대상 파일에 직접 쓰고 싶을 때 좋은 방법 일 수 있습니다. SAX Parser는 전체 XML 컨텐트를 메모리로 읽지 않지만 입력 스트림의 요소를 enconters 할 때 메서드를 트리거합니다. 지금까지 내가 경험 한대로 이것은 매우 기억에 효율적인 처리 방법이다.

SAX는 Stax-Solution과 비교하여 데이터를 애플리케이션에 '푸시 (push)'합니다. 즉, 상태를 유지해야한다는 것입니다 (즉, 어떤 태그가 사용자와 같은지). 따라서 현재 상태를 추적해야합니다 위치.

import java.io.FileReader; 
import org.xml.sax.Attributes; 
import org.xml.sax.ContentHandler; 
import org.xml.sax.InputSource; 
import org.xml.sax.Locator; 
import org.xml.sax.SAXException; 
import org.xml.sax.XMLReader; 
import org.xml.sax.helpers.XMLReaderFactory; 

public class SaxExample implements ContentHandler 
{ 
    private String currentValue; 

    public static void main(final String[] args) throws Exception 
    { 
     final XMLReader xmlReader = XMLReaderFactory.createXMLReader(); 

     final FileReader reader = new FileReader("datasource.xml"); 
     final InputSource inputSource = new InputSource(reader); 

     xmlReader.setContentHandler(new SaxExample()); 
     xmlReader.parse(inputSource); 
    } 

    @Override 
    public void characters(final char[] ch, final int start, final int length) throws  SAXException 
    { 
     currentValue = new String(ch, start, length); 
    } 

    @Override 
    public void startElement(final String uri, final String localName, final String  qName, final Attributes atts) throws SAXException 
    { 
     // react on the beginning of tag "GroupBMsg" <GroupBMSg> 
     if (localName.equals("GroupBMsg")) 
     { 
      currentValue=""; 
     } 
    } 

    @Override 
    public void endElement(final String uri, final String localName, final String  qName) throws SAXException 
    { 
     // react on the ending of tag "GroupBMsg" </GroupBMSg> 
     if (localName.equals("GroupBMsg")) 
     { 
      // TODO: write into file 
      System.out.println(currentValue); 
     } 
    } 


    // the rest is boilerplate code for sax 

    @Override 
    public void endDocument() throws SAXException {} 
    @Override 
    public void endPrefixMapping(final String prefix) throws SAXException {} 
    @Override 
    public void ignorableWhitespace(final char[] ch, final int start, final int length) 
     throws SAXException {} 
    @Override 
    public void processingInstruction(final String target, final String data) 
     throws SAXException {} 
    @Override 
    public void setDocumentLocator(final Locator locator) { } 
    @Override 
    public void skippedEntity(final String name) throws SAXException {} 
    @Override 
    public void startDocument() throws SAXException {} 
    @Override 
    public void startPrefixMapping(final String prefix, final String uri) 
     throws SAXException {} 
} 
관련 문제