2010-03-22 40 views
12

Tôi đã tìm kiếm các giải pháp cho vấn đề này quá lâu để xem xét nó dễ dàng như thế nào vì vậy tôi đã đến để được giúp đỡ.Xác nhận hợp lệ chống lại một Schema với JAXB

Tôi có một lược đồ XML mà tôi đã sử dụng với xjc để tạo liên kết JAXB của tôi. Điều này làm việc tốt khi XML được định dạng tốt. Thật không may, nó cũng không phàn nàn khi XML không được định dạng tốt. Tôi không thể tìm ra cách thực hiện xác nhận hợp lệ đầy đủ đối với lược đồ khi tôi cố gắng unmarshall một tệp XML.

Tôi đã quản lý để sử dụng ValidationEventCollector để xử lý sự kiện, hoạt động cho các lỗi phân tích cú pháp XML như thẻ không khớp nhưng không tăng bất kỳ sự kiện nào khi có thẻ bắt buộc nhưng hoàn toàn vắng mặt.

Từ những gì tôi đã thấy xác thực có thể được thực hiện chống lại lược đồ, nhưng bạn phải biết đường dẫn đến giản đồ để chuyển nó vào phương thức setSchema(). Vấn đề tôi có là đường dẫn đến lược đồ được lưu trữ trong tiêu đề XML và tôi không thể gõ vào thời gian chạy mà lược đồ sẽ có. Đó là lý do tại sao nó được lưu trữ trong file XML:

<?xml version="1.0" encoding="utf-8"?> 
<DDSSettings xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="https://stackoverflow.com/a/big/long/path/to/a/schema/file/DDSSettings.xsd"> 
<Field1>1</Field1> 
<Field2>-1</Field2> 

... vv

Mỗi ví dụ tôi thấy sử dụng setValidating (true), mà bây giờ bị phản đối, vì vậy ném một ngoại lệ.

Đây là mã Java tôi có cho đến nay, mà dường như chỉ làm xác nhận XML, không schema xác nhận:

try { 
    JAXBContext jc = new JAXBContext() { 
     private final JAXBContext jaxbContext = JAXBContext.newInstance("blah"); 

     @Override 
     public Unmarshaller createUnmarshaller() throws JAXBException { 
      Unmarshaller unmarshaller = jaxbContext.createUnmarshaller(); 
      ValidationEventCollector vec = new ValidationEventCollector() { 
       @Override 
       public boolean handleEvent(ValidationEvent event) throws RuntimeException { 
        ValidationEventLocator vel = event.getLocator(); 
        if (event.getSeverity() == event.ERROR || event.getSeverity() == event.FATAL_ERROR) { 
         String error = "XML Validation Exception: " + event.getMessage() + " at row: " + vel.getLineNumber() + " column: " + vel.getColumnNumber(); 
         System.out.println(error); 
        } 
        m_unmarshallingOk = false; 
        return false; 
       } 
      }; 
      unmarshaller.setEventHandler(vec); 

      return unmarshaller; 
     } 

     @Override 
     public Marshaller createMarshaller() throws JAXBException { 
      throw new UnsupportedOperationException("Not supported yet."); 
     } 

     @Override 
     @SuppressWarnings("deprecation") 
     public Validator createValidator() throws JAXBException { 
      throw new UnsupportedOperationException("Not supported yet."); 
     } 
    }; 

    Unmarshaller unmarshaller = jc.createUnmarshaller(); 
    m_ddsSettings = (com.ultra.DDSSettings)unmarshaller.unmarshal(new File(xmlfileName)); 
} catch (UnmarshalException ex) { 
    Logger.getLogger(UniversalDomainParticipant.class.getName()).log(
    Level.SEVERE, 
    null, ex); 
} catch (JAXBException ex) { 
    Logger.getLogger(UniversalDomainParticipant.class.getName()).log(
    Level.SEVERE, 
    null, ex); 
} 

Vì vậy, các cách thích hợp để làm xác nhận đây là những gì? Tôi đã mong đợi có một phương thức validate() trên các lớp được tạo bởi JAXB, nhưng tôi đoán điều đó sẽ quá đơn giản đối với Java.

Trả lời

14

OK, tôi đã tìm thấy giải pháp. Sử dụng nhà máy lược đồ để tạo một lược đồ, nhưng không xác định một tệp lược đồ làm cho nó hoạt động với noNamespaceSchemaLocation được chỉ định trong tệp XML.

Vì vậy, các mã từ trên đã có này nói thêm:

SchemaFactory factory = SchemaFactory.newInstance("http://www.w3.org/2001/XMLSchema"); 
Schema schema = factory.newSchema(); 
Unmarshaller unmarshaller = jc.createUnmarshaller(); 
unmarshaller.setSchema(schema); 
m_ddsSettings = (com.ultra.DDSSettings)unmarshaller.unmarshal(new File(xmlfileName)); 

xấu hổ mà mất phần tốt nhất là 24 giờ để tìm câu trả lời cho!

Các javadoc cho SchemaFactory.newSchema() nói:

Đối với XML Schema, phương pháp này tạo ra một đối tượng Schema mà thực hiện xác nhận bằng cách sử dụng gợi ý vị trí quy định tại tài liệu.

Đối tượng Schema trở giả rằng nếu tài liệu tham khảo với cùng URL trong các gợi ý vị trí lược đồ, họ sẽ luôn giải quyết với cùng tài liệu giản đồ . Tính năng asusmption này cho phép triển khai để sử dụng lại các kết quả của các tài liệu lược đồ để nhiều xác thực đối với cùng một lược đồ sẽ chạy nhanh hơn.

+0

Thú vị, tôi không biết điều đó. Tôi đã tự do thêm một số thông tin vào câu trả lời của bạn, để tham khảo trong tương lai. – skaffman

+1

Thay vì chỉ định rõ ràng URL XMLSchema, theo javadocs, hãy sử dụng giá trị thích hợp từ XMLConstants như được chỉ định tại đây: http://docs.oracle.com/javase/6/docs/api/index.html?javax/xml/validation /Schema.html – icfantv

+0

@icfantv của chúng tôi là đúng, tôi sử dụng: Schema schema = SchemaFactory.newInstance (XMLConstants.W3C_XML_SCHEMA_NS_URI) .newSchema(); // nhưng tham chiếu là: http://docs.oracle.com/javase/6/docs/api/index.html?javax/xml/validation/Schema.html - Ngoài ra điều tôi không hiểu về giải pháp này là url là hằng số: nó không đề cập đến vị trí của lược đồ của chúng ta (không hiển nhiên đối với tôi) – pdem

1

Theo như tôi biết, bạn chỉ cần đặt giản đồ với Marshaller.setSchema() thành giản đồ được tạo bởi SchemaFactory từ DDSSettings.xsd. Thao tác này sẽ bật xác thực.

+0

Nhưng vấn đề là tôi không biết đường dẫn đến tệp XSD đó tại thời gian biên dịch và không được đưa vào thời gian chạy - nó chỉ được lưu trữ trong tiêu đề tệp XML. – fwgx

+0

Nhưng nếu bạn có các lớp jaxb, chúng phải được tạo ra từ một lược đồ. Tại sao không bao gồm lược đồ trong dự án của bạn? –

+0

JAXB không * có * để làm việc với một lược đồ và mã được tạo ra, nó hoạt động hoàn toàn tốt mà không có lược đồ. – skaffman

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