2016-09-15 1 views
0

データをバッチでxmlに書き込む必要があります。Spring Jaxb2:バッチデータをXMLファイルに追加してメモリに読み込む方法はありますか?

@XmlRootElement(name = "country") 
public class Country { 
    @XmlElements({@XmlElement(name = "town", type = Town.class)}) 
    private Collection<Town> towns = new ArrayList<>(); 
    .... 
} 

そして:私はJAXB2でオブジェクトをmarhallingてる

@XmlRootElement(name = "town") 
public class Town { 
    @XmlElement 
    private String townName; 
    // etc 
} 

には、以下のドメインオブジェクトがあります。設定は次のように簡単なマーシャリングがmarhaller.marshall(fileName, country)として、ここでは動作しません

marshaller = new Jaxb2Marshaller(); 
marshaller.setClassesToBeBound(Country.class, Town.class); 

ので - それは、XMLをmalformes。

marhalledデータがすべて存在しない場合、またはxmlファイルの最後に追加するだけの場合、ファイルを作成するようにtweek marhallerへの方法はありますか?

このファイルは潜在的に大きいので、私はメモリ内のファイル全体を読み込み、データを追加してからディスクに書き込むことは望ましくありません。

答えて

1

私はストリームベースでXML処理にStAXを使用しましたが、DOMより少ないメモリしか消費せず、XMLデータのみを解析できますが書き込めないSAXと比較して読み書きする能力があります。

ザ・私が思い付いたアプローチである:それはそれは、ストリームベースのだという事実をdispiteし、それが働いて、最善のアプローチではありません

public enum StAXBatchWriter { 
    INSTANCE; 
    private static final Logger LOGGER = LoggerFactory.getLogger(StAXBatchWriter.class); 

    public void writeUrls(File original, Collection<Town> towns) { 
     XMLEventReader eventReader = null; 
     XMLEventWriter eventWriter = null; 
     try { 
      String originalPath = original.getPath(); 
      File from = new File(original.getParent() + "/old-" + original.getName()); 
      boolean isRenamed = original.renameTo(from); 
      if (!isRenamed) 
       throw new IllegalStateException("Failed to rename file: " + original.getPath() + " to " + from.getPath()); 
      File to = new File(originalPath); 

      XMLInputFactory inFactory = XMLInputFactory.newInstance(); 
      eventReader = inFactory.createXMLEventReader(new FileInputStream(from)); 

      XMLOutputFactory outFactory = XMLOutputFactory.newInstance(); 
      eventWriter = outFactory.createXMLEventWriter(new FileWriter(to)); 

      XMLEventFactory eventFactory = XMLEventFactory.newInstance(); 

      while (eventReader.hasNext()) { 
       XMLEvent event = eventReader.nextEvent(); 
       eventWriter.add(event); 
       if (event.getEventType() == XMLEvent.START_ELEMENT && event.asStartElement().getName().toString().contains("country")) { 
        for (Town town : towns) { 
         writeTown(eventWriter, eventFactory, town); 
        } 
       } 
      } 
      boolean isDeleted = from.delete(); 
      if (!isDeleted) 
       throw new IllegalStateException("Failed to delete old file: " + from.getPath()); 
     } catch (IOException | XMLStreamException e) { 
      LOGGER.error(e.getMessage(), e); 
      throw new RuntimeException(e); 
     } finally { 
      try { 
       if (eventReader != null) 
        eventReader.close(); 
      } catch (XMLStreamException e) { 
       LOGGER.error(e.getMessage(), e); 
      } 
      try { 
       if (eventWriter != null) 
        eventWriter.close(); 
      } catch (XMLStreamException e) { 
       LOGGER.error(e.getMessage(), e); 
      } 
     } 
    } 

    private void writeTown(XMLEventWriter eventWriter, XMLEventFactory eventFactory, Town town) throws XMLStreamException { 
     eventWriter.add(eventFactory.createStartElement("", null, "town")); 

     // write town id 
     eventWriter.add(eventFactory.createStartElement("", null, "id")); 
     eventWriter.add(eventFactory.createCharacters(town.getId())); 
     eventWriter.add(eventFactory.createEndElement("", null, "id")); 

     //write town name 
     if (StringUtils.isNotEmpty(town.getName())) { 
      eventWriter.add(eventFactory.createStartElement("", null, "name")); 
      eventWriter.add(eventFactory.createCharacters(town.getName())); 
      eventWriter.add(eventFactory.createEndElement("", null, "name")); 
     } 

     // write other fields 

     eventWriter.add(eventFactory.createEndElement("", null, "town")); 
    } 
} 

、それはいくつかのオーバーヘッドがあります。バッチが追加されると、古いファイルを再読み込みする必要があります。

ファイルのあるポイント(4行後にそのファイルにデータを追加するような)にデータを追加するオプションがあるといいですが、これはできないようです。

関連する問題