Jaxb 2.0 Schema 验证问题

Posted

技术标签:

【中文标题】Jaxb 2.0 Schema 验证问题【英文标题】:Jaxb 2.0 Schema validation problem 【发布时间】:2011-06-19 09:04:41 【问题描述】:

我正在使用 Jaxb 2.x 并尝试使用以下教程使用给定 XSD 验证 XML 文档

Tutorial Link

她是我写的代码

unmarshaller.setSchema(schema);
        SAXSource source = new SAXSource(new InputSource(xmlFileLocation));
        Validator validator = schema.newValidator();
        validator.setErrorHandler(new XMLErrorHandler<Object>());
         try 
                validator.validate(source);
             catch (SAXException e) 

我的 XMLErrorHanlder 类具有以下签名

public class XMLErrorHandler<T> implements ErrorHandler 
public void error(SAXParseException exception) throws SAXException 
        xmlUnmarshaller.setValidationFlag(true);
        log.error(
                "Line:Col[" + exception.getLineNumber()
                + ":" + exception.getColumnNumber()
                + "]:" + exception.getMessage());


        exception.printStackTrace();

    
                       


警告和致命代码已被删除 现在它使用 XSD 验证 XML,但它只显示第一个遇到的错误,而我想在 colsole 上打印所有错误并在控制台上发出警告

我不确定我在哪里做错了任何帮助都会有所帮助

编辑1 这是XSD文件的一部分

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<xs:schema version="1.0" xmlns:xs="http://www.w3.org/2001/XMLSchema">

  <xs:element name="destination" type="Destination"/>

  <xs:complexType name="Destination">
    <xs:sequence>
      <xs:element name="name" type="xs:string"/>
      <xs:element name="destinationID" type="xs:string" minOccurs="0"/>
      <xs:element name="shortDescription" type="xs:string" minOccurs="0"/>
      <xs:element name="longDescription" type="xs:string" minOccurs="0"/>
      <xs:element name="stateID" type="xs:string"/>
      <xs:element name="typeCode" type="xs:int"/>
      <xs:element name="countryCode" type="xs:string"/>
      <xs:element name="categories" type="xs:string"/>
      <xs:element name="transport" type="Transport" minOccurs="0" maxOccurs="1"/>
      <xs:element name="cultures" type="Cultures" minOccurs="0"/>
      <xs:element name="events" type="Events" minOccurs="0" maxOccurs="1"/>
      <xs:element name="placesToVisit" type="PlacesToVisit" minOccurs="0" maxOccurs="1"/>
      <xs:element name="contacts" type="Contact" minOccurs="0" maxOccurs="1"/>
      <xs:element name="addresses" type="address" minOccurs="0" maxOccurs="1"/>
    </xs:sequence>
  </xs:complexType>

XML 文件是

<destination xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="destination.xsd">
  <name>Palampur</name>
  <destinationID>PLP</destinationID>
  <shortDescription>shortDescription</shortDescription>
  <longDescription>longDescription</longDescription>
  <typeCode>0</typeCode>
  <categories>categories</categories>

我在进行一些研发后的假设是 XSD 结构或生成的 XML 存在一些问题,但我不确定

【问题讨论】:

【参考方案1】:

您可以利用几种方法来根据 XML 模式验证您的 XML 文档。

javax.xml.validation API

第一个是使用 javax.xml.validation API 来根据没有 JAXB 的 XML 模式验证您的文档。

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema version="1.0" xmlns:xs="http://www.w3.org/2001/XMLSchema">

  <xs:element name="destination" type="Destination"/>

  <xs:complexType name="Destination">
    <xs:sequence>
      <xs:element name="name" type="xs:string"/>
      <xs:element name="destinationID" type="xs:string" minOccurs="0"/>
      <xs:element name="shortDescription" type="xs:string" minOccurs="0"/>
      <xs:element name="longDescription" type="xs:string" minOccurs="0"/>
      <xs:element name="stateID" type="xs:string"/>
      <xs:element name="typeCode" type="xs:int"/>
      <xs:element name="countryCode" type="xs:string"/>
      <xs:element name="categories" type="xs:string"/>
    </xs:sequence>
  </xs:complexType>

</xs:schema>

和 XML 文档:

<?xml version="1.0" encoding="UTF-8"?>
<destination xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="destination.xsd">
  <sd></sd>
  <name>Palampur</name>
  <destinationID>PLP</destinationID>
  <shortDescription>shortDescription</shortDescription>
  <longDescription>longDescription</longDescription>
  <typeCode>ZERO</typeCode>
  <categories>categories</categories>
</destination>

使用以下演示代码:

import java.io.File;

import javax.xml.XMLConstants;
import javax.xml.transform.sax.SAXSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;

import org.xml.sax.ErrorHandler;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;

public class Demo 

    public static void main(String[] args) throws Exception 
        String xmlFileLocation = "src/validate/blog/input.xml";
        SAXSource source = new SAXSource(new InputSource(xmlFileLocation));

        SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
        Schema schema = sf.newSchema(new File("src/validate/blog/customer.xsd"));
        Validator validator = schema.newValidator();
        validator.setErrorHandler(new MyErrorHandler());

        validator.validate(source);
        System.out.println("DONE");
    

    private static class MyErrorHandler implements ErrorHandler 

        public void error(SAXParseException arg0) throws SAXException 
            System.out.println("ERROR");
            arg0.printStackTrace(System.out);
        

        public void fatalError(SAXParseException arg0) throws SAXException 
            System.out.println("FATAL ERROR");
            arg0.printStackTrace(System.out);
        

        public void warning(SAXParseException arg0) throws SAXException 
            System.out.println("WARNING ERROR");
            arg0.printStackTrace(System.out);
        

    


将给出显示多个错误的以下输出:

ERROR
org.xml.sax.SAXParseException: cvc-complex-type.2.4.a: Invalid content was found starting with element 'sd'. One of 'name' is expected.
    at com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.createSAXParseException(Unknown Source)
    at com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.error(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator$XSIErrorReporter.reportError(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator.reportSchemaError(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator.handleStartElement(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator.startElement(Unknown Source)
    at com.sun.org.apache.xerces.internal.jaxp.validation.ValidatorHandlerImpl.startElement(Unknown Source)
    at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.startElement(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.scanStartElement(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl$FragmentContentDriver.next(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.next(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(Unknown Source)
    at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(Unknown Source)
    at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(Unknown Source)
    at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(Unknown Source)
    at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(Unknown Source)
    at com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser.parse(Unknown Source)
    at com.sun.org.apache.xerces.internal.jaxp.validation.ValidatorHandlerImpl.validate(Unknown Source)
    at com.sun.org.apache.xerces.internal.jaxp.validation.ValidatorImpl.validate(Unknown Source)
    at javax.xml.validation.Validator.validate(Unknown Source)
    at validate.blog.Demo.main(Demo.java:27)
ERROR
org.xml.sax.SAXParseException: cvc-datatype-valid.1.2.1: 'ZERO' is not a valid value for 'integer'.
    at com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.createSAXParseException(Unknown Source)
    at com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.error(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator$XSIErrorReporter.reportError(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator.reportSchemaError(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator.elementLocallyValidType(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator.processElementContent(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator.handleEndElement(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator.endElement(Unknown Source)
    at com.sun.org.apache.xerces.internal.jaxp.validation.ValidatorHandlerImpl.endElement(Unknown Source)
    at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.endElement(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanEndElement(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl$FragmentContentDriver.next(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.next(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(Unknown Source)
    at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(Unknown Source)
    at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(Unknown Source)
    at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(Unknown Source)
    at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(Unknown Source)
    at com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser.parse(Unknown Source)
    at com.sun.org.apache.xerces.internal.jaxp.validation.ValidatorHandlerImpl.validate(Unknown Source)
    at com.sun.org.apache.xerces.internal.jaxp.validation.ValidatorImpl.validate(Unknown Source)
    at javax.xml.validation.Validator.validate(Unknown Source)
    at validate.blog.Demo.main(Demo.java:27)
ERROR
org.xml.sax.SAXParseException: cvc-type.3.1.3: The value 'ZERO' of element 'typeCode' is not valid.
    at com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.createSAXParseException(Unknown Source)
    at com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.error(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator$XSIErrorReporter.reportError(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator.reportSchemaError(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator.elementLocallyValidType(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator.processElementContent(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator.handleEndElement(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator.endElement(Unknown Source)
    at com.sun.org.apache.xerces.internal.jaxp.validation.ValidatorHandlerImpl.endElement(Unknown Source)
    at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.endElement(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanEndElement(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl$FragmentContentDriver.next(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.next(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(Unknown Source)
    at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(Unknown Source)
    at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(Unknown Source)
    at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(Unknown Source)
    at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(Unknown Source)
    at com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser.parse(Unknown Source)
    at com.sun.org.apache.xerces.internal.jaxp.validation.ValidatorHandlerImpl.validate(Unknown Source)
    at com.sun.org.apache.xerces.internal.jaxp.validation.ValidatorImpl.validate(Unknown Source)
    at javax.xml.validation.Validator.validate(Unknown Source)
    at validate.blog.Demo.main(Demo.java:27)
DONE

JAXB API

第二种方法是在使用 JAXB 执行解组操作时进行验证。

import java.io.File;

import javax.xml.XMLConstants;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.ValidationEvent;
import javax.xml.bind.ValidationEventHandler;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;

import org.xml.sax.InputSource;

public class JaxbDemo 

    public static void main(String[] args) throws Exception 
        JAXBContext jc = JAXBContext.newInstance(Destination.class);
        Unmarshaller unmarshaller = jc.createUnmarshaller();

        SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
        Schema schema = sf.newSchema(new File("src/validate/blog/customer.xsd"));
        unmarshaller.setSchema(schema);
        unmarshaller.setEventHandler(new MyValidationEventHandler());

        String xmlFileLocation = "src/validate/blog/input.xml";
        unmarshaller.unmarshal(new InputSource(xmlFileLocation));

    

    private static class MyValidationEventHandler implements ValidationEventHandler 

        public boolean handleEvent(ValidationEvent arg0) 
            System.out.println(arg0.getSeverity());
            return true;
        

    


更多信息:

http://bdoughan.blogspot.com/2010/11/validate-jaxb-object-model-with-xml.html http://bdoughan.blogspot.com/2010/12/jaxb-and-marshalunmarshal-schema.html

【讨论】:

Blaise:我试过你的方式,但注意到一种奇怪的方式 countryCode 也是根据 XSD 在 XML 中的必填项,但验证没有说明 XML 中没有这个字段。如果我删除 typeCode验证根本不会说明这个丢失的字段,它只符合 stateID 并且将存在并且不会指向任何其他丢失的字段或无效数据。我期望验证器应该运行一次运行哪些标签丢失和哪些无效数据在任何 XML 中。我不希望用户一次显示一个错误,而是希望一次性显示所有错误,以便他可以更正一次 Umesh - 有关 javax.xml.validation API 何时抛出异常的具体细节,您可能需要查阅 JAXP 规范或将非 JAXB 示例发布到 Stack Overflow 以获得更广泛的 Java/XML观众。 嗨@BlaiseDoughan,该错误背后的原因是什么。我得到同样的错误,但没有得到原因:(还有为什么DONE即使抛出错误也最终被打印出来......!【参考方案2】:

我认为可能已经报告了fatalError。您没有在问题中提供此类信息。如果是这种情况,您可以在ErrorHandler 的 javadoc 中阅读您的问题的解释:

但是请注意,没有 要求解析器继续 之后报告其他错误 致电fatalError。换一种说法, SAX 驱动程序类可能会抛出一个 报告任何异常后 fatalError.

我希望这可以解释你的麻烦。

编辑 1: 在您发布架构后,我想我知道这让您感到困扰。验证器针对每个错误元素报告一个错误。你的情况是:

<xs:element name="destination" type="Destination"/>

错误将类似于(表示缺少 stateID):

Error: Line:Col[7:13]:cvc-complex-type.2.4.a: Invalid content was found starting with element 'typeCode'. One of 'stateID' is expected.

它不会报告多个错误,因为每个复杂类型只有一个错误报告。如果您像这样更改复杂类型:

<xs:all>

您可能会收到一条不同的消息,但又是一条消息:

Error: Line:Col[9:15]:cvc-complex-type.2.4.b: The content of element 'destination' is not complete. One of 'stateID, countryCode' is expected.

如果您修改架构以接受多个 destination 元素,则每个元素可能会收到 1 条错误消息。

干杯!

【讨论】:

@lucho: 我也在处理我的代码中的致命错误,并且堆栈跟踪没有显示任何此类错误 那你最好把你的XML文件的内容贴出来(位于xmlFileLocation)。如果 xsd 与教程中的不同,也将其发布。本教程按预期工作:/ 这个呢? :) -> xmlUnmarshaller.setValidationFlag(true);你不应该需要它。 @umesh awasthi:查看与您的更新对应的我的更新 :-) @Lucho:agree 这就是当前发生的情况我现在将 stateID 和 typeCode 作为必填字段,如果 XML 中缺少两个标签,它只会报告缺少预期的标签 stateID,但没有其他错误标志缺少标签类型代码。在第二种情况下,如果 stateId 丢失并且 typeCode 包含无效数据,它将符合 stateId 丢失和数据类型,但不会对任何其他丢失的标签说任何话。如果任何标签丢失或任何无效数据,我希望它应该显示 XML 的所有错误XML。

以上是关于Jaxb 2.0 Schema 验证问题的主要内容,如果未能解决你的问题,请参考以下文章

JAXB - XML Schema Types, Defining Subtypes

JAXB - XML Schema Types, Binary Data

JAXB - XML Schema Types, Date and Time

解组非根元素时的 JAXB 模式验证

验证 List(Jaxb) 中未编组的条目

java.lang.LinkageError: JAXB 2.0 API is being loaded from the bootstrap classloader