2012-12-19 8 views
5

大きな複合XMLを解析してフラットファイルに書き込む必要がありますか?大きな複合XMLを解析する方法

ファイルサイズ:500メガバイト 録音回数: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/JAXB/Springバッチを使用しています。私は多くの記事を読んでいますが、上記のXMLを効果的に処理する方法についてはまだ分かりません。 – Weber

答えて

0

あなたがを解析し、書きたいので、私は、このような巨大なファイルサイズを扱っが、あなたの問題を考慮していませんフラットファイルには、XML Pull Parsingとスマートコードをフラットファイル(this might help)に書き込むことを想定しています。これは、Javaヒープを使い果たしたくないからです。チュートリアルやサンプルコードのXML Pull Parsingの使い方については、Google検索をすばやく行うことができます。

+0

はい、JAXB/Spring Batchが優先されますが、上記の複雑なxmlを効果的に解析する方法はありません。私は大規模なXML解析の初心者です。コメントは感謝します。 – Weber

0

最後に、カスタマイズされたStaxEventItemReaderを実装します。

  1. コンフィグfragmentRootElementName

  2. コンフィグ自分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. MyStaxEventItemReader.doReadで以下の断片()

    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"から1つのオブジェクト(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 /春のバッチをソリューションを受け入れた場合

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

、あなたはSAXパーサを見てしたいことがあります。

これはイベント中心のXMLファイルの解析方法であり、解析中にターゲットファイルに直接書き込む場合には適しています。 SAX Parserはxmlの内容全体をメモリに読み込むのではなく、入力ストリームの要素をエンコーディングするときにメソッドをトリガーします。私が経験した限り、これは非常にメモリ効率の良い処理方法です。

あなたのStax-Solutionと比較して、SAXはあなたのアプリケーションにデータをプッシュします。つまり、状態を維持する必要があります。つまり、あなたの現在の状況を把握する必要がありますロケーション。「あなたは

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 {} 
} 
関連する問題