2009-10-13 25 views
45

Tôi cần xác thực các đối tượng JAXB của mình trước khi sắp xếp một tập tin XML. Trước JAXB 2.0, người ta có thể sử dụng một javax.xml.bind.Validator. Nhưng điều đó đã không được chấp nhận nên tôi đang cố gắng tìm ra cách làm đúng đắn. Tôi quen thuộc với việc xác nhận thời gian marshall nhưng trong trường hợp của tôi, tôi chỉ muốn biết nếu nó hợp lệ. Tôi cho rằng tôi có thể sắp xếp một tập tin tạm thời hoặc bộ nhớ và vứt nó đi nhưng tự hỏi liệu có một giải pháp thanh lịch hơn không.Làm cách nào để xác thực hợp lệ đối với lược đồ trong JAXB 2.0 mà không cần marshalling?

Trả lời

68

Trước hết, javax.xml.bind.Validator đã không được chấp nhận vì lợi ích của javax.xml.validation.Schema (javadoc). Ý tưởng là bạn phân tích cú pháp lược đồ của mình thông qua một số javax.xml.validation.SchemaFactory (javadoc) và đưa vào lược đồ/unmarshaller.

Đối với câu hỏi của bạn liên quan đến xác nhận mà không marshalling, vấn đề ở đây là JAXB thực sự đại biểu xác nhận để Xerces (hoặc bất cứ bộ xử lý SAX bạn đang sử dụng), và Xerces xác nhận tài liệu của bạn dưới dạng một dòng sự kiện SAX. Vì vậy, để xác thực, bạn cần thực hiện một số loại loại marshalling.

Việc triển khai tác động thấp nhất này sẽ là sử dụng triển khai "/ dev/null" của bộ xử lý SAX. Marshalling đến một OutputStream null sẽ vẫn liên quan đến việc tạo ra XML, đó là lãng phí. Vì vậy, tôi xin đề nghị:

SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); 
Schema schema = schemaFactory.newSchema(locationOfMySchema); 

Marshaller marshaller = jaxbContext.createMarshaller(); 
marshaller.setSchema(schema); 
marshaller.marshal(objectToMarshal, new DefaultHandler()); 

DefaultHandler sẽ loại bỏ tất cả các sự kiện, và các hoạt động marshal() sẽ ném một JAXBException nếu xác nhận dựa trên giản đồ thất bại.

4

Cách thức chúng tôi đã thực hiện. Tôi đã phải tìm cách xác thực tệp xml so với xsd tương ứng với phiên bản xml vì chúng tôi có nhiều ứng dụng sử dụng các phiên bản khác nhau của nội dung xml.

Tôi thực sự không tìm thấy bất kỳ ví dụ hay nào trên mạng và cuối cùng đã kết thúc với điều này. Hy vọng điều này sẽ giúp.

ValidationEventCollector vec = new ValidationEventCollector(); 

SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); 

URL xsdURL = getClass().getResource("/xsd/" + xsd); 
Schema schema = sf.newSchema(xsdURL); 

//You should change your jaxbContext here for your stuff.... 
Unmarshaller um = (getJAXBContext(NotificationReponseEnum.NOTIFICATION, notificationWrapper.getEnteteNotification().getTypeNotification())) 
    .createUnmarshaller(); 
um.setSchema(schema); 

try { 
    StringReader reader = new StringReader(xml); 
    um.setEventHandler(vec); 
    um.unmarshal(reader); 
} catch (javax.xml.bind.UnmarshalException ex) { 
    if (vec != null && vec.hasEvents()) { 
     erreurs = new ArrayList <MessageErreur>(); 
     for (ValidationEvent ve: vec.getEvents()) { 
      MessageErreur erreur = new MessageErreur(); 
      String msg = ve.getMessage(); 
      ValidationEventLocator vel = ve.getLocator(); 
      int numLigne = vel.getLineNumber(); 
      int numColonne = vel.getColumnNumber(); 
      erreur.setMessage(msg); 
      msgErreur.setCode(ve.getSeverity()) 
      erreur.setException(ve.getLinkedException()); 
      erreur.setPosition(numLigne, numColonne); 
      erreurs.add(erreur); 

      logger.debug("Erreur de validation xml" + "erreur : " + numLigne + "." + numColonne + ": " + msg); 
     } 
    } 
} 
10

Bạn có thể sử dụng một javax.xml.bind.util.JAXBSource (javadoc) và một javax.xml.validation.Validator (javadoc), ném vào một thực hiện org.xml.sax.ErrorHandler (javadoc) và làm như sau:

import java.io.File; 

import javax.xml.XMLConstants; 
import javax.xml.bind.JAXBContext; 
import javax.xml.bind.util.JAXBSource; 
import javax.xml.validation.*; 

public class Demo { 

    public static void main(String[] args) throws Exception { 
     Customer customer = new Customer(); 
     customer.setName("Jane Doe"); 
     customer.getPhoneNumbers().add(new PhoneNumber()); 
     customer.getPhoneNumbers().add(new PhoneNumber()); 
     customer.getPhoneNumbers().add(new PhoneNumber()); 

     JAXBContext jc = JAXBContext.newInstance(Customer.class); 
     JAXBSource source = new JAXBSource(jc, customer); 

     SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); 
     Schema schema = sf.newSchema(new File("customer.xsd")); 

     Validator validator = schema.newValidator(); 
     validator.setErrorHandler(new MyErrorHandler()); 
     validator.validate(source); 
    } 

} 

Để biết thêm thông tin, Xem My Blog

+2

Một vấn đề với cách tiếp cận này: bạn không nhận được thông tin số dòng/cột về lỗi xác thực bằng phương pháp này, do đó rất khó để theo dõi vấn đề. –

+0

Cách tiếp cận đó có thể áp dụng cho Unmarchalling không. Tôi không thể tạo đối tượng JAXBSource. – Xelian

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