2009-07-15 58 views

回答

17

這在user guide中有詳細說明。從http://jaxb.java.net/下載的JAXB包含一個如何一次解析一個塊的示例。

當文檔是大的,這是 通常是因爲有重複 部分在裏面。也許這是一個購買 的訂單,其中包含大量訂單項, 或者它可能是一個包含 大量日誌條目的XML日誌文件。

這種XML適用於 塊處理;主要思路是 分別使用StAX API,運行一個循環,並分別解組單個塊 。您的程序將作用於單個塊上的 ,然後將其丟棄。 通過這種方式,您將只保留 內存中最多的一個塊,這允許您使用 來處理大型文檔。

見流,解組 例子和部分解組 例如在JAXB RI分佈 更多有關如何做到這一點。該 流,解組例如有 優點是,它可以在任意 窩水平處理塊,但它需要 你對付推模式--- JAXB解組將「推」新 塊給你,你」你需要 在那裏處理它們。

相比之下,局部解組 例如工作在拉取模型(其通常 使處理更容易), 但這種方法有一些侷限性 在其它數據綁定部分比 重複部分。

+0

對,這是我在研究這個網站時發現的網站之一,但我無法找到它在第4.4.1節中提到的「流 - 解組」和「部分解組」。 – 2009-07-15 21:32:58

+7

奇怪。你在看哪裏?我剛剛從jaxb.dev.java.net/2.1.12下載了JAR,解壓縮了它,在「samples」下面是「partial-unmarshalling」和「stream-unmarshalling」。 – skaffman 2009-07-15 21:42:31

24

因爲代碼很重要,所以這裏是一個PartialUnmarshaller誰讀大塊文件成塊。它可以使用這種方式new PartialUnmarshaller<YourClass>(stream, YourClass.class)

import javax.xml.bind.JAXBContext; 
import javax.xml.bind.JAXBException; 
import javax.xml.bind.Unmarshaller; 
import javax.xml.stream.*; 
import java.io.InputStream; 
import java.util.List; 
import java.util.NoSuchElementException; 
import java.util.stream.Collectors; 
import java.util.stream.IntStream; 

import static javax.xml.stream.XMLStreamConstants.*; 

public class PartialUnmarshaller<T> { 
    XMLStreamReader reader; 
    Class<T> clazz; 
    Unmarshaller unmarshaller; 

    public PartialUnmarshaller(InputStream stream, Class<T> clazz) throws XMLStreamException, FactoryConfigurationError, JAXBException { 
     this.clazz = clazz; 
     this.unmarshaller = JAXBContext.newInstance(clazz).createUnmarshaller(); 
     this.reader = XMLInputFactory.newInstance().createXMLStreamReader(stream); 

     /* ignore headers */ 
     skipElements(START_DOCUMENT, DTD); 
     /* ignore root element */ 
     reader.nextTag(); 
     /* if there's no tag, ignore root element's end */ 
     skipElements(END_ELEMENT); 
    } 

    public T next() throws XMLStreamException, JAXBException { 
     if (!hasNext()) 
      throw new NoSuchElementException(); 

     T value = unmarshaller.unmarshal(reader, clazz).getValue(); 

     skipElements(CHARACTERS, END_ELEMENT); 
     return value; 
    } 

    public boolean hasNext() throws XMLStreamException { 
     return reader.hasNext(); 
    } 

    public void close() throws XMLStreamException { 
     reader.close(); 
    } 

    void skipElements(int... elements) throws XMLStreamException { 
     int eventType = reader.getEventType(); 

     List<Integer> types = asList(elements); 
     while (types.contains(eventType)) 
      eventType = reader.next(); 
    } 
} 
2

伊夫AMSELLEM的答案是相當不錯的,但只有當所有元素都完全一樣類型的作品。否則,你的unmarshall會拋出一個異常,但讀者已經消耗了字節,所以你將無法恢復。相反,我們應該遵循Skaffman的建議並查看來自JAXB jar的示例。

解釋它是如何工作的:

  1. 創建JAXB解組。
  2. 將偵聽器添加到解組器,以截獲適當的元素。這是通過「hacking」ArrayList來完成的,以確保元素在解組後不被存儲在內存中。
  3. 創建一個SAX解析器。這是流式傳輸發生的地方。
  4. 使用unmarshaller爲SAX解析器生成處理程序。
  5. 流!

我將該解決方案修改爲通用*。但是,這需要一些反思。如果這不行,請查看JAXB JARB中的代碼示例。

ArrayListAddInterceptor.java

import java.lang.reflect.Field; 
import java.util.ArrayList; 

public class ArrayListAddInterceptor<T> extends ArrayList<T> { 
    private static final long serialVersionUID = 1L; 

    private AddInterceptor<T> interceptor; 

    public ArrayListAddInterceptor(AddInterceptor<T> interceptor) { 
     this.interceptor = interceptor; 
    } 

    @Override 
    public boolean add(T t) { 
     interceptor.intercept(t); 
     return false; 
    } 

    public static interface AddInterceptor<T> { 
     public void intercept(T t); 
    } 

    public static void apply(AddInterceptor<?> interceptor, Object o, String property) { 
     try { 
      Field field = o.getClass().getDeclaredField(property); 
      field.setAccessible(true); 
      field.set(o, new ArrayListAddInterceptor(interceptor)); 
     } catch (Exception e) { 
      throw new RuntimeException(e); 
     } 
    } 

} 

Main.java

public class Main { 
    public void parsePurchaseOrders(AddInterceptor<PurchaseOrder> interceptor, List<File> files) { 
     try { 
      // create JAXBContext for the primer.xsd 
      JAXBContext context = JAXBContext.newInstance("primer"); 

      Unmarshaller unmarshaller = context.createUnmarshaller(); 

      // install the callback on all PurchaseOrders instances 
      unmarshaller.setListener(new Unmarshaller.Listener() { 
       public void beforeUnmarshal(Object target, Object parent) { 
        if (target instanceof PurchaseOrders) { 
         ArrayListAddInterceptor.apply(interceptor, target, "purchaseOrder"); 
        } 
       } 
      }); 

      // create a new XML parser 
      SAXParserFactory factory = SAXParserFactory.newInstance(); 
      factory.setNamespaceAware(true); 
      XMLReader reader = factory.newSAXParser().getXMLReader(); 
      reader.setContentHandler(unmarshaller.getUnmarshallerHandler()); 

      for (File file : files) { 
       reader.parse(new InputSource(new FileInputStream(file))); 
      } 
     } catch (Exception e) { 
      throw new RuntimeException(e); 
     } 
    } 
} 

*此代碼尚未經過測試並且僅是爲了說明性目的。