0

I am facing a problem with Java XML validation API. When an array of XSDs (schema files) is passed to method javax.xml.validation.SchemaFactory.newSchema(Source[] schemas), it throws the following exception:

org.xml.sax.SAXParseException; src-resolve: Cannot resolve the name 'Report' 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:396)
    at com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(XMLErrorReporter.java:306)
    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:4141)
    at com.sun.org.apache.xerces.internal.impl.xs.traversers.XSDHandler.getGlobalDecl(XSDHandler.java:1674)
    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.traverseGlobal(XSDElementTraverser.java:242)
    at com.sun.org.apache.xerces.internal.impl.xs.traversers.XSDHandler.traverseSchemas(XSDHandler.java:1429)
    at com.sun.org.apache.xerces.internal.impl.xs.traversers.XSDHandler.parseSchema(XSDHandler.java:626)
    at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaLoader.loadSchema(XMLSchemaLoader.java:613)
    at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaLoader.loadGrammar(XMLSchemaLoader.java:572)
    at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaLoader.loadGrammar(XMLSchemaLoader.java:538)
    at com.sun.org.apache.xerces.internal.jaxp.validation.XMLSchemaFactory.newSchema(XMLSchemaFactory.java:252)
    ...

Below is shown part of the code used to generate the schema.

public static Object converToObject(byte[] xmlByteBuffer, int offset, int length, Class<?>... type) throws JAXBException {

    JAXBContext context = JAXBContext.newInstance(type);

    final List<DOMResult> results = new ArrayList<DOMResult>();

    try {
        context.generateSchema(new SchemaOutputResolver() {
            @Override
            public Result createOutput(String namespaceUri, String suggestedFileName) throws IOException {
                DOMResult result = new DOMResult();
                result.setSystemId(suggestedFileName);

                results.add(result);

                return result;
            }
        });
    } catch (IOException e1) {
        e1.printStackTrace();
    }

    final SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);

    DOMSource[] sources = new DOMSource[results.size()];

    for (int i = 0; i < results.size(); i++) {
        DOMResult result = results.get(i);
        Node node = result.getNode();

        sources[i] = new DOMSource(node);

    }

    // First Solution: Reverse Order
//  DOMSource[] resortedSources = new DOMSource[results.size()];
//  for(int i=1; i<results.size(); i++){
//      sourcesSorted[results.size()-(i+1)] = sources[i];
//  }

    // Second Solution: Look for the XSD with imports with namespace
    // attribute        
    for (int i = 0; i < results.size(); i++) {
        Node node = sources[i].getNode();

        if(thereIsElementImportWithAttributeNamespace(node)) {
            DOMSource sourceBackup = sources[0];
            sources[0] = sources[i];
            sources[i] = sourceBackup;
            break;
        }
    }


    Schema schema = null;
    try {
        schema = schemaFactory.newSchema(sources);
//      schema = schemaFactory.newSchema(resortedSources);
    } catch (SAXException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

    Unmarshaller unmarshaller = context.createUnmarshaller();

    unmarshaller.setSchema(schema);
    unmarshaller.setEventHandler(new javax.xml.bind.helpers.DefaultValidationEventHandler());

    String str;
    try {
        str = new String(xmlByteBuffer, offset, length, "UTF-8");
    } catch (UnsupportedEncodingException uee) {
        try {
            str = new String(xmlByteBuffer, "ISO-8859-1");
        } catch (UnsupportedEncodingException ex) {
            throw new JAXBException(ex);
        }
    }

    StreamSource ss = new StreamSource(new StringReader(str));

    Object obj = unmarshaller.unmarshal(ss);
    return obj;
}

Below are shown printed parts of true XSDs which are passed to method newSchema.

schema1.xsd:

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://service.mw.uw/" version="1.0">
    <xs:import schemaLocation="schema4.xsd"/>
    <xs:element name="Report" type="Report"/>
    ...
</xs:schema>

schema2.xsd:

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://service.gather.mw.uw/" version="1.0">
    <xs:import schemaLocation="schema4.xsd"/>
    <xs:element name="DataReport" type="DataReport"/>
    ...
</xs:schema>

schema3.xsd:

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://service.commons.uw/" targetNamespace="http://service.commons.uw/" version="1.0">
    <xs:import schemaLocation="schema4.xsd"/>
    <xs:element name="ApplicationRequest" type="ApplicationRequest"/>
    ...
</xs:schema>

schema4.xsd:

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:ns1="http://service.commons.uw/" xmlns:ns2="http://service.gather.mw.uw/" version="1.0">
    <xs:import namespace="http://service.commons.uw/" schemaLocation="schema3.xsd"/>
    <xs:import namespace="http://service.gather.mw.uw/" schemaLocation="schema2.xsd"/>
    <xs:complexType name="message">
        ...
    </xs:complexType>
    ...

</xs:schema>

It is spread abroad that SchemaFactory.newSchema cannot deal with multiple XSDs importing multiple XSDs.

According to Hedleys, a solution would be to sort any array of XSDs with imported XSDs before the ones which actually import them. I faced a problem with this solution, because in my project there are several mutual imports among XSDs. So how could that be sorted?

Also, according to jtahlborn, another solution is to resort XSD arrays in opposite order. That worked fine! However, I kept researching the problem because, in the time, I had just few different cases to test if that solution was generic enough!

The Java Documentation of the method SchemaFactory.newSchema states the following: "Section 4.2.3 of the XML Schema recommendation describes the options processors have in this regard. While a processor should be consistent in its treatment of JAXP schema sources and XML Schema imports, the behaviour between JAXP-compliant parsers may vary; in particular, parsers may choose to ignore all but the first for a given namespace, regardless of information provided in schemaLocation". So based on that statement, I could fix the exception mentioned early, by placing the XSD with imports containing namespace attribute in the first position of the XSD array. So finally, here comes my question:

Is the cause of the exception, the lack of namespace attribute in the imports of the first XSD read from the array of XSDs?

I could only test that last solution with few different cases, but all worked just fine! If someone has more test cases to try, please let we know if that last solution really works in any case.

Community
  • 1
  • 1
  • You've not demonstrated that your problem is as complicated as you describe. Reduce it to a [mcve]: Show the minimum, complete set of XSDs and Java validation calls that exhibit the problem. What you've posted is nowhere close to that. – kjhughes Aug 25 '16 at 23:28
  • You've added XSD fragments, but your problem is ***still not verifiable***: You've omitted many dangling references, *including the declaration of the **very type mentioned in the error message***. Again, create the smallest possible example that completely demonstrates the problem, and post **that**. – kjhughes Aug 26 '16 at 12:31
  • @kjhughes I cannot turn public the classes which I pass in the argument type and I cannot turn public the XSDs generated by those classes. That is the most I can post here. I think I delimited very well the problem, which is method **newSchema** throwing the very same exception when it receives an array of XSD. I also mentioned that when I reverse the order of any array of XSDs from my test cases, that works well, or when I find the XSD containing import with namespace, and put that XSD in the first position, that works well too. Finally, I also referenced other opened questions! – Vítor Moscon Aug 26 '16 at 13:45
  • Last time, then I'm moving on: Recreate the problem in sanitized, reduced, and verifiable form, or we can't trust that you're representing the true problem here. It's a good bit of work, but it's ***your*** work to do, not *ours*. – kjhughes Aug 26 '16 at 13:56

1 Answers1

0

I don't see a type named Report (in no namespace) in any of those schema documents, so the error message seems entirely legitimate to me.

Michael Kay
  • 156,231
  • 11
  • 92
  • 164
  • I have summarized the XSDs replacing their contents by "**...**". Note, when I invert the order of the array (1º solution); or relocate the XSD containing imports with namespace to the first position of the array, all works well! My questions are: what is the best approach? Is it guaranteed the 2º solution will always find only one XSD containing imports with namespace and just relocate that to the first position? What is really the problem? None of both solutions seem to me generic enough! – Vítor Moscon Aug 26 '16 at 13:33