问题
There are many postings with the same title as this. I have looked at many of them, but their situations seem to be different from mine.
I have a Java application that is configured at run-time by an XML file. There is a corresponding XML schema that defines the structure of the XML. The schema imports other schema to use type definitions they define. The application reads in the schema and configuration file and loads the XML as Java objects.
The application is built using Apache Maven and the maven-jaxb2-plugin is used to translate the schema definitions into Java classes so the application can ingest the XML configuration information. Everything builds successfully and from what I can tell, the XJC generated classes are correct and in the correct locations.
I'm running into a problem when I attempt execute the application, which first reads in the XML and load it as Java objects. An example exception follows.
[2018-08-09 10:31:05.056] ERROR: common.ConfigLoader:121 - Exception:
org.xml.sax.SAXParseException; lineNumber: 291; columnNumber: 80; src-resolve: Cannot resolve the name 'sc:ExpectedDataFormatEnum' to a(n) 'type definition' component.
at com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.createSAXParseException(ErrorHandlerWrapper.java:198)
at com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.error(ErrorHandlerWrapper.java:134)
at com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(XMLErrorReporter.java:437)
at com.sun.org.apache.xerces.internal.impl.xs.traversers.XSDHandler.reportSchemaErr(XSDHandler.java:4162)
at com.sun.org.apache.xerces.internal.impl.xs.traversers.XSDHandler.reportSchemaError(XSDHandler.java:4145)
at com.sun.org.apache.xerces.internal.impl.xs.traversers.XSDHandler.getGlobalDecl(XSDHandler.java:1678)
at com.sun.org.apache.xerces.internal.impl.xs.traversers.XSDElementTraverser.traverseNamedElement(XSDElementTraverser.java:405)
at com.sun.org.apache.xerces.internal.impl.xs.traversers.XSDElementTraverser.traverseLocal(XSDElementTraverser.java:194)
at com.sun.org.apache.xerces.internal.impl.xs.traversers.XSDHandler.traverseLocalElements(XSDHandler.java:3618)
at com.sun.org.apache.xerces.internal.impl.xs.traversers.XSDHandler.parseSchema(XSDHandler.java:633)
at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaLoader.loadSchema(XMLSchemaLoader.java:617)
at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaLoader.loadGrammar(XMLSchemaLoader.java:575)
at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaLoader.loadGrammar(XMLSchemaLoader.java:541)
at com.sun.org.apache.xerces.internal.jaxp.validation.XMLSchemaFactory.newSchema(XMLSchemaFactory.java:252)
at javax.xml.validation.SchemaFactory.newSchema(SchemaFactory.java:627)
at {removed}.ConfigLoader.load(ConfigLoader.java:91)
at {removed}.Launcher.main(Launcher.java:121)
[2018-08-09 10:31:05.058] ERROR: wf.Launcher:122 - Unable to load configuration file
I suspect the problem is related to how the imported schemae are being referenced/resolved at run-time. I use an XML catalog (a new concept for me) to resolve schema locations during the build. Do I need something similar to resolve the location at run time?
For context, here are snippets of relevant files.
Schema that is imported by the application schema (security-common.xsd):
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="security_common"
xmlns:sc="security_common" elementFormDefault="qualified" attributeFormDefault="unqualified">
<xs:simpleType name="TypeList">
<xs:list itemType="xs:string" />
</xs:simpleType>
<xs:simpleType name="ExpectedDataFormatEnum">
<xs:restriction base="xs:string">
<xs:enumeration value="STRING" />
<xs:enumeration value="BYTE_ARRAY" />
</xs:restriction>
</xs:simpleType>
</xs:schema>
Application schema that uses the schema above (config-schema.xsd):
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="injector"
xmlns:inj="injector" xmlns:sc="security_common" xmlns:camel="camel_config"
elementFormDefault="qualified" attributeFormDefault="unqualified">
<xs:import namespace="security_common" />
<xs:import namespace="camel_config" />
...
<xs:complexType name="WireCaptureConfig">
<xs:sequence>
<xs:element name="expected-data-format" type="sc:ExpectedDataFormatEnum" />
...
</xs:sequence>
</xs:complexType>
...
</xs:schema>
The XML catalog file:
PUBLIC "security_common" "maven:{removed}:security-common:jar::!/config/security-common.xsd"
PUBLIC "camel_config" "maven:{removed}:security-common:jar::!/config/camel-config.xsd"
My understanding is that the catalog file maps the schema namespaces to maven artifacts, which represent the schemae to be imported/referenced. It seems like a little black magic, but it does work.
The exception thrown would seem to indicate that the application cannot "see" the imported schema definitions. Based upon what has been described, is there a solution to this problem? If other information needs to be provided, please let me know and I'll see what I can do.
回答1:
You're right to suspect that you have to make accomodations for your XML catalog in your runtime Java code too.
See Using an XML Catalog with a Java library that uses JAXP internally for details on how to use a CatalogResolver (or org.apache.xml.resolver.tools.CatalogResolver).
Note also that it can be useful to establish that all else is in order with your XSDs by placing them in URI-accessible locations1 and adding @schemaLocation
attributes to your xs:imports
. Many XML Catalog implementation's diagnostic messages are less than ideal for tracking down problems.
1See How to reference a local XML Schema file correctly?
来源:https://stackoverflow.com/questions/51771197/cannot-resolve-the-name-x-to-an-type-definition-component