2012-12-19 18 views
5

Büyük bir karmaşık xml dosyasını ayrıştırıp bir Düz dosyaya yazmam gerekiyor, biraz öneride bulunabilir misiniz?büyük karmaşık xml'yi nasıl ayrıştırılır

Dosya boyutu: 500 MB Kayıt saymak: 100K XML yapısı:

<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

belirli dil' vardır: o gerçekten

Aşağıdaki örnek yapıda bir xml dosyasında okur ve GroupBMsg-Etiketler içindeki tüm metni yazdırır gerektiren bir şey olup olmadığından emin değilim Kullanacak mısın? –

+0

Dosyanın yapısı kontrol edilmeli mi, yoksa sé için geçerli olduğunu mu düşünüyorsunuz? – Thilo

+0

Java kullanıyorum, JAXB/Spring Batch tercih edilen bir seçenektir, çok sayıda yazı okudum ama yine de xml'nin üzerinde nasıl etkili bir şekilde işlem yapılacağı hakkında hiçbir fikrim yok. – Weber

cevap

0

Böyle büyük dosya boyutları ile ele fakat sorunu dikkate değil, sen ayrıştırmak ve yazmak istiyorum çünkü düz bir dosyaya, ben XML Pull Parsing ve düz dosyaya (this might help) yazmak için akıllı kod bir kombinasyon tahmin çünkü Java yığınını tüketmek istemiyoruz. XML Çekme Ayrıştırma'yı kullanarak dersler ve örnek kod için hızlı bir Google araması yapabilirsiniz.

+0

Evet, JAXB/Spring Batch tercih edilen bir seçenektir, ancak karmaşık xml'yi etkin bir şekilde nasıl ayrıştırabileceğiniz hakkında hiçbir fikrimiz yoktur. Büyük xml ayrıştırmada yeni biriyim. Herhangi bir yorum takdir edilecektir. – Weber

0

Sonunda, özelleştirilmiş bir StaxEventItemReader uyguladım.

  1. Yapılandırma fragmentRootElementName

  2. Yapılandırma MyStaxEventItemReader.doRead içinde kendi 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. Ekleme aşağıdaki fragman()

    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

gibi bazı ETL aracı denemeye, ben daha spesifik daha biraz çalışır benim kendi stax olay öğesi okuyucu uygulaması yazdım Daha önce de belirtildiği. Temel olarak, elemanları bir haritaya yerleştiriyorum ve sonra bunları ItemProcessor'a aktarıyorum. Oradan, "GatheredElement" den tek bir nesneye (bkz. CompositeItemProcessor) dönüştürmek için özgürsünüz. StaxEventItemReader'dan küçük bir kopyalama/yapıştırmaya sahip olmaktan dolayı özür dilerim, ancak bunun önlenebilir olduğunu düşünmüyorum.

Buradan, istediğiniz OXM mareşalini kullanmakta serbestsiniz, JAXB'yi de kullanıyorum.

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; 
    } 

toplanan eleman sınıfı

oldukça basit: Eğer bir kenara JAXB/Bahar Toplu bir çözümü kabul ederseniz, SAX Ayrıştırıcı bir göz atmak istersin

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

.

Bu, XML dosyalarını ayrıştırmaya yönelik daha olay odaklı bir yoldur ve ayrıştırma sırasında hedef dosyaya doğrudan yazmak istediğinizde iyi bir yaklaşım olabilir. SAX Ayrıştırıcı, tüm xml içeriğini belleğe okumaz, ancak giriş akışındaki öğeleri kodladığında yöntemleri tetikler. Deneyimlediğim kadarıyla, bu bellek açısından verimli bir işlem şeklidir.

SAX'iniz, Stax-Solution'ınıza kıyasla, verileri uygulamanıza aktarır - bu, durumu korumanız gerektiği anlamına gelir (hangi etikette olduğu gibi). yer.

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 {} 
}