Tôi cần phân tích các tệp XML có khả năng lớn, trong đó lược đồ đã được cung cấp cho tôi trong một số tệp XSD, vì vậy việc gắn kết XML được ưa chuộng. Tôi muốn biết nếu tôi có thể sử dụng JAXB để phân tích các tập tin trong khối và nếu như vậy, làm thế nào.JAXB có thể phân tích cú pháp các tệp XML lớn theo các khối
Trả lời
Chi tiết này được nêu chi tiết trong user guide. Tải xuống JAXB từ http://jaxb.java.net/ bao gồm ví dụ về cách phân tích cú pháp một đoạn tại một thời điểm.
Khi tài liệu lớn, nó là thường vì có lặp lại các phần trong đó. Có lẽ đó là đơn đặt hàng mua có danh sách chi tiết đơn hàng lớn, hoặc có lẽ đó là tệp nhật ký XML có số lượng lớn các mục nhập nhật ký là .
Loại XML này phù hợp cho xử lý đoạn; ý tưởng chính là để sử dụng API StAX, chạy vòng lặp và các đoạn riêng lẻ không đối xứng riêng biệt. Chương trình của bạn hoạt động trên một đoạn đơn và sau đó ném nó đi. Bằng cách này, bạn sẽ chỉ giữ được phần lớn một bộ nhớ, cho phép bạn xử lý các tài liệu lớn.
Xem ví dụ về phát trực tiếp không đồng bộ hóa và ví dụ một phần trong bản phân phối JAXB RI để biết thêm về cách thực hiện việc này. Ví dụ streaming-unmarshalling có một lợi thế rằng nó có thể xử lý khối tại mức tổ tùy ý, tuy nhiên nó đòi hỏi bạn để đối phó với các mô hình push --- JAXB unmarshaller sẽ "đẩy" mới đoạn để bạn và bạn' sẽ cần phải xử lý chúng ngay tại đó.
Ngược lại, một phần-unmarshalling dụ làm việc trong một mô hình pull (mà thường làm cho việc xử lý dễ dàng hơn), nhưng phương pháp này có một số hạn chế trong các phần liên kết dữ liệu khác với lặp đi lặp lại một phần.
Vì mã quan trọng, dưới đây là PartialUnmarshaller
người đọc tệp lớn thành các đoạn. Nó có thể được sử dụng theo cách đó 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();
}
}
Tôi cần sử dụng XMLStreamConstants.START_DOCUMENT, v.v. để làm việc này. –
@MatthiasWuttke bạn có thể thêm chúng dưới dạng nhập tĩnh. nhập tệp javax.xml.stream.XMLStreamConstants tĩnh. *; –
Bạn cũng có thể cần Intava's List của Guava hoặc trong java8 IntStream.of (elements) .boxed(). Collect (Collectors.toList()); –
Yves Câu trả lời của Ysel là khá tốt, nhưng chỉ hoạt động nếu tất cả các thành phần cùng loại chính xác. Nếu không, unmarshall của bạn sẽ ném một ngoại lệ, nhưng người đọc sẽ đã tiêu thụ các byte, vì vậy bạn sẽ không thể phục hồi. Thay vào đó, chúng ta nên làm theo lời khuyên của Skaffman và nhìn vào mẫu từ bình JAXB.
Để giải thích cách hoạt động:
- Tạo một unmarshaller JAXB.
- Thêm người nghe vào bộ lọc không đối sánh để chặn các phần tử thích hợp. Điều này được thực hiện bằng cách "hack" ArrayList để đảm bảo các phần tử không được lưu trữ trong bộ nhớ sau khi được unmarshalled.
- Tạo trình phân tích SAX. Đây là nơi phát trực tuyến.
- Sử dụng trình gỡ lỗi để tạo trình xử lý cho trình phân tích SAX.
- Phát trực tuyến!
Tôi đã sửa đổi giải pháp thành chung *. Tuy nhiên, nó đòi hỏi một số phản ánh. Nếu điều này không ổn, hãy xem các mẫu mã trong các lọ JAXB.
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);
}
}
}
* Mã này chưa được thử nghiệm và chỉ nhằm mục đích minh họa.
Phải, đó là một trong những trang web tôi tìm thấy khi nghiên cứu điều này, nhưng tôi không thể tìm thấy ví dụ "streaming-unmarshalling" và "partial-unmarshalling" được đề cập trong phần 4.4.1. –
Rất tiếc. Bạn đang nhìn đi đâu vậy? Tôi vừa tải xuống JAR từ jaxb.dev.java.net/2.1.12, giải nén nó, và có dưới "mẫu" là "một phần-unmarshalling" và "stream-unmarshalling". – skaffman