JAXB如何针对更多模式验证xml

时间:2014-04-25 09:11:41

标签: java xml validation jaxb xsd

我使用以下代码:

    Unmarshaller unmarshaller = inputXmlContext.createUnmarshaller();
    SchemaFactory sf = SchemaFactory.newInstance(javax.xml.XMLConstants.W3C_XML_SCHEMA_NS_URI);
    URL urlSchema = ProbeOutputTranslator.class.getResource("/a.xsd");
    Schema schema = sf.newSchema(new File(urlSchema.toURI()));

针对a.xsd验证xml。问题是a.xsd定义了一个抽象元素及其包含的元素:

<xs:complexType name="abstract_operation" abstract="true"/>

<xs:element name="operation" type="ac:abstract_operation"/>

<xs:complexType name="so_operations">
    <xs:sequence>
        <xs:element ref="ac:operation" minOccurs = "0" maxOccurs="unbounded"/> 
    </xs:sequence>
</xs:complexType>

具体类型在b.xsd中定义。在xml文件中,默认命名空间是a.xsdb.xsd的命名空间 绑定前缀ops,它看起来像这样:

<so_operations>
    <ops:a_concrete_operation>
                 ....
    </ops:a_concrete_operation>
</so_operations>

当使用上述代码时,此设置当然会导致验证错误。在验证时,如何实现b.xsd模式?

模式仅位于程序的资源中(因此无法在xml文件中定义模式位置)。

1 个答案:

答案 0 :(得分:2)

您可以通过编程方式将多个模式组合到单个模式中,然后根据组合模式进行验证。

SchemaFactory.newSchema()有一个变量,它接受一组源文档,并将它们组合成一个Schema实例。但是,记录此方法的行为就像使用每个源文档的导入指令创建新的模式文档一样。因此,您无法将源文件与相同的目标命名空间组合在一起,并且必须对源文档进行排序,以便在从另一个命名空间请求时,一个命名空间中的定义可用(我在文档中未找到任何证据来证明这一点)

如果您的架构文档可通过URL或文件系统访问,则最佳解决方案是创建单个顶级架构文档,并使用显式import和include指令来引用您的定义。

下面的代码可能有助于开始:

URL xsdUrlA = this.getClass().getResource("a.xsd");
URL xsdUrlB = this.getClass().getResource("b.xsd");

SchemaFactory schemaFactory = schemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
//---
String W3C_XSD_TOP_ELEMENT =
"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n"
+ "<xs:schema xmlns:xs=\"http://www.w3.org/2001/XMLSchema\" elementFormDefault=\"qualified\">\n"
+ "<xs:include schemaLocation=\"" +xsdUrlB.getPath() +"\"/>\n"
+ "<xs:include schemaLocation=\"" +xsdUrlA.getPath() +"\"/>\n"
+"</xs:schema>";
Schema schema = schemaFactory.newSchema(new StreamSource(new StringReader(W3C_XSD_TOP_ELEMENT), "xsdTop"));