如何使用资源jar中的factorored-out .xsd文件来指定JAXB模式?

时间:2015-09-29 19:23:53

标签: java xml xsd jaxb unmarshalling

我正在将XML文件解组为JAXB生成的Java对象。我希望unmarshaller根据进程中的模式验证文件。模式的.xsd文件位于依赖项.jar文件中。我这样设置架构:

ClassLoader classLoader = getClass().getClassLoader();
InputStream schemaStream = classLoader.getResourceAsStream(schemaFilePath);
StreamSource schemaSource = new StreamSource(schemaStream);
Schema schema = factory.newSchema(schemaSource);
unmarshaller.setSchema(schema);

除了一个问题之外,这主要是有效的。该模式将一些复杂类型分解为其他.xsd文件。 unmarshaller似乎无法找到已分解的.xsd文件,因为当我尝试设置架构时,我得到了SAXException

Cannot resolve the name 'tns:FactoredOutType' to a(n) 'type definition' component.

注意:从eclipse运行时,当它引用.xsd文件夹而不是target文件中的.jar文件时,此方法正常。

任何人都有任何想法如何让依赖的.xsd文件中的模式使用的因子.jar文件?

编辑:

如果它是有用的信息,则顶级.xsd位于model文件夹中,其引用的类型位于model/common,因此我引用了顶级.xsd 1}} as:

"model/TopLevel.xsd"

...并且在其中,它将因子分解.xsd引用为:

"common/FactoredOut.xsd"

3 个答案:

答案 0 :(得分:0)

我们有一些XSD导入/包含其他XSD。我们通过将它们全部传递给SchemaFactory来实现这一点,而不是依赖于导入工作并在类路径中找到它。这是代码的样子:

    try (InputStream xsdStream0 = ClaimLoadService.class.getResourceAsStream("/a.xsd");
            InputStream xsdStream1 = ClaimLoadService.class.getResourceAsStream("/b.xsd");
            InputStream xsdStream2 = ClaimLoadService.class.getResourceAsStream("/c.xsd");
            InputStream xsdStream3 = ClaimLoadService.class.getResourceAsStream("/d.xsd");
            InputStream xsdStream4 = ClaimLoadService.class.getResourceAsStream("/e.xsd");) {
        SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
        schema = sf.newSchema(new Source[] { new StreamSource(xsdStream0), new StreamSource(xsdStream1),
                new StreamSource(xsdStream2), new StreamSource(xsdStream3), new StreamSource(xsdStream4) });
        ...
    } catch (SAXException | IOException | JAXBException e) {
        logger.log(Level.INFO, e.getMessage(), e);
    }

为了使JAXB完全满意,我们有时必须做的另一件事是确保导入模式实际引用导入的类型。我不记得确切的错误,表明我们需要做出解决方法,但也许这就是你要打的。它很俗气,但我们这样做是一种解决方法:

<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns="http://blah" xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:name="http://blahblah" targetNamespace="http://blah"
elementFormDefault="qualified">

    <xs:import namespace="http://blahblah" />

    ...

    <xs:element name="ReferencesToMakeTheseElementsVisibleToThisJaxbContext">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="Business" type="name:type" minOccurs="0" />
                ...
            </xs:sequence>
        </xs:complexType>
    </xs:element>
</xs:schema>

基本上,我们创建一个complexType只是为了明确引用一些导入的类型。我们只需要在没有直接引用类型的情况下执行此操作。

答案 1 :(得分:0)

通常,与XML相关的API有一种方法可以让程序员指定辅助文件的位置,称为资源解析。对于Schema,我认为您必须实现LSResourceResolver并在调用SchemaFactory.setResourceResolver之前将其传递给newSchema

答案 2 :(得分:0)

我最后通过将我的newSchema调用从StreamSource传递到传递URL来修复此问题,URL schemaURL = objectType.getClassLoader().getResource(schemaPath); if (schemaURL != null) { Schema schema = factory.newSchema(schemaURL); unmarshaller.setSchema(schema); } 保留了基本URI,因此仍然可以找到包含的类型(正如@PetruGardea在评论中提到的那样)。结果代码如下所示:

#latest {
 overflow-x: scroll;
 overflow-y: hidden;
 height: 80px;
 white-space:nowrap
}
article{
box-shadow: 1px 1px 10px #999;
margin: 2px;
max-height: 150px;
cursor: pointer;
display:inline-block;
*display:inline;/* For IE7*/
*zoom:1;/* For IE7*/
vertical-align:top;

谢谢大家的帮助!