2012-03-13 30 views
20

Tôi có một ứng dụng đang thực hiện XML < -> chuyển đổi bằng cách sử dụng Jaxb và các lớp được tạo tự động với plugin maven-jaxb2.Jaxb: cách unmarshall xs: bất kỳ phần chuỗi XML nào?

Một nơi nào đó sâu trong lược đồ của tôi, tôi có khả năng nhập "BẤT K" "xml.

Cập nhật: điều này mô tả tốt hơn lược đồ của tôi. Một số XML được biết đến bao gồm một phần hoàn toàn không rõ (phần "bất kỳ").

<xs:complexType name="MessageType"> 
    <xs:sequence> 
    <xs:element name="XmlAnyPayload" minOccurs="0"> 
     <xs:complexType> 
      <xs:sequence> 
       <xs:any namespace="##any"/> 
      </xs:sequence> 
     </xs:complexType> 
    </xs:element> 
    <xs:element name="OtherElements"> 
     .... 
</xs:sequence> 

bản đồ này (bằng cách jaxb) vào một lớp bên trong như thế này.

@XmlAccessorType(XmlAccessType.FIELD) 
@XmlType(name = "", propOrder = { 
    "any" 
}) 
public static class XmlAnyPayload { 

    @XmlAnyElement(lax = true) 
    protected Object any; 

Khi tôi unmarshall toàn bộ cấu trúc, không có vấn đề gì. "Đối tượng bất kỳ" sẽ hiển thị thành một org.apache.xerces.dom.ElementNSImpl. Bây giờ, tôi muốn tạo lại đối tượng Java theo cách thủ công và sau đó đi tới XML. Làm cách nào để lấy một số XML ngẫu nhiên và đưa vào bất kỳ phần tử (org.apache.xerces.dom.ElementNSImpl) nào để có thể xây dựng đối tượng Java?

Ngoài ra, trường hợp tiếp theo là khi tôi có phần tử này dưới dạng java, tôi muốn unmarshall phần này (để có thể trích xuất chuỗi XML của phần tử này). Nhưng điều này là không thể. Tôi nhận được một ngoại lệ về các yếu tố gốc. Nhưng không thể chú thích ElementNSImpl.

unable to marshal type "com.sun.org.apache.xerces.internal.dom.ElementNSImpl" as an element because it is missing an @XmlRootElement annotation 

Bạn có bất cứ đề xuất nào về cách xử lý những vấn đề này không?

+0

Nhờ đầu vào tốt vào miền này, tôi đã giải quyết được vấn đề này. Một cách, tôi bị mắc kẹt với nút Dom của tôi. Chỉ cần thêm một số phân tích cú pháp XML đơn giản để lấy phần tử dom từ chuỗi. Một cách khác, tôi sử dụng XML để làm việc với không gian DOM (XPATH khôn ngoan), vì nó thực sự đã cứu tôi một số thời gian và bối cảnh chuyển mạch. XPath thực sự rất tốt để giữ độ phức tạp của mã. –

Trả lời

37

@XmlAnyElement(lax = true) nghĩa ở đồng bằng một cái gì đó bằng tiếng Anh như:

Thưa JAXB! Nếu bạn có ánh xạ cho phần tử này, vui lòng hủy hợp nhất nó thành đối tượng Java. Nếu bạn không biết yếu tố này, chỉ cần để nguyên tố này là một phần tử DOM .

Đây chính xác là những gì đang xảy ra trong trường hợp của bạn. Vì vậy, nếu bạn muốn thực sự unmarshal nội dung của lax này bất kỳ, cung cấp JAXB bối cảnh với một bản đồ cho các phần tử bạn muốn unmarshal.Cách đơn giản nhất để làm điều này là để chú thích lớp học của bạn với @XmlRootElement

@XmlRootElement(name="foo", namespace="urn:bar") 
public class MyClass { ... } 

Bây giờ khi bạn tạo ra bối cảnh JAXB của bạn, thêm MyClass vào nó:

JAXBContext context = JAXBContext.newInstance(A.class, B.class, ..., MyClass.class); 

Trong trường hợp này, nếu JAXB đáp ứng các yếu tố {urn:bar}foo ở nơi đó xs:any, nó sẽ biết rằng yếu tố này được ánh xạ lên MyClass và sẽ cố gắng để unmarshal MyClass.

Nếu bạn đang tạo ngữ cảnh JAXB dựa trên tên gói (bạn có thể làm), bạn vẫn có thể thêm lớp học của bạn (giả sử, com.acme.foo.MyClass) vào đó. Cách đơn giản nhất là tạo ra một nguồn lực com/acme/foo/jaxb.index:

com.acme.foo.MyClass 

Và thêm tên gói của bạn vào đường dẫn ngữ cảnh:

JAXBContext context = JAXBContext.newInstance("org.dar.gee.schema:com.acme.foo"); 

Có nhiều cách khác với ObjectFactory vv, nhưng lừa với jaxb.index là có lẽ là cách dễ nhất. Ngoài ra, thay vì unmarshalling tất cả mọi thứ trong một chạy, bạn có thể để lại nội dung của xs:any như DOM và unmarshal nó vào đối tượng mục tiêu trong một unmarshalling thứ hai với bối cảnh JAXB anothe (mà biết lớp MyClass của bạn). Một cái gì đó như:

JAXBContext payloadContext = JAXBContext.newInstance(MyClass.class); 
payloadContext.createUnmarshaller().unmarshal((Node) myPayload.getAny()); 

Phương pháp này đôi khi tốt hơn, đặc biệt khi bạn kết hợp các lược đồ container/tải trọng tương đối độc lập. Phụ thuộc vào vụ án.

Tất cả những điều trên cũng áp dụng cho việc đầm lầy. Đó là tất cả hai chiều gọn gàng.

+2

Câu trả lời này là một trình tiết kiệm cuộc sống. Không cần phải nói tôi đã bỏ phiếu, tôi xin lỗi tôi không thể làm điều đó hai lần. Một lời giải thích tuyệt vời cộng với một giải pháp tốt - cảm ơn bạn, lexicore! – quantum

+2

@Quantum Bạn được chào đón. Tiết kiệm cuộc sống chỉ có một chút dễ dàng hơn. :) – lexicore

+0

@lexicore Vì vậy, nếu XmlAnyElement được đặt thành false/bỏ qua, nó sẽ để nó như một đối tượng DOM? –

0
<xs:any/> 

yêu cầu một số nội dung không trực quan để chuyển đổi thành đối tượng java. Nếu bạn không có sự khác biệt, hãy thử sử dụng

<element name="any" type="xs:anyType"/> 
1

Tôi nghĩ bạn cần XSD cho phần "bất kỳ" này và tạo lớp học cho chúng.

Dưới đây là một số thông tin hơn:

http://jaxb.java.net/guide/Mapping_of__xs_any___.html

Edit: nếu đối tượng của bạn, bạn muốn sắp xếp không có chú thích @XmlRootElement (xem thông báo lỗi), sau đó tôi nghĩ rằng bạn phải quấn nó với một JAXBElement.

+0

Cảm ơn bạn đã trả lời. Tuy nhiên, tôi sẽ không bao giờ biết chính xác nội dung của thông điệp "bất kỳ" nào, cũng như tôi không muốn biết. Tôi chỉ muốn có thể xử lý nó như một đoạn. –

+0

Hướng dẫn được liên kết để cung cấp một số kiến ​​thức chi tiết đẹp trong miền này. –

Các vấn đề liên quan