title: Java XML Schema validator with custom resource resolver fails to resolve elements
body: <p>Java XML Schema validation - ResourceResolver trouble</p>
  
  <p>I am trying to build a component into a web application that will validate different XML documents against a set of schemas.</p>
  
  <p>I have the validator class in java package com.example.xml and then I have a "package" for the schemas com.example.xml.Schemas where they are organized according to the namespace along with any included schemas, like so:</p>
  
  <pre><code>com.example.xml/SchemaValidator.java
  
  com.example.xml.Schemas/2008/07/05/Message.xsd
  com.example.xml.Schemas/2008/07/05/Person.xsd
  com.example.xml.Schemas/2008/07/05/Address.xsd
  
  com.example.xml.Schemas/2010/09/21/Message.xsd
  com.example.xml.Schemas/2010/09/21/Organization.xsd
  com.example.xml.Schemas/2010/09/21/Person.xsd
  com.example.xml.Schemas/2010/09/21/Address.xsd
  </code></pre>
  
  <p>So most of the document-elements are called Message but in different namespaces and different internals.
  Via a mapping I can determine where the correct schema is located, and then I load the XSD matching the root element name - but to make the parser able to read the included schemas, I made an attempt at an org.w3c.dom.ls.LSResourceResolver implementation to fetch the correct files based on the systemId.</p>
  
  <pre><code>public class ResourceResolver implements LSResourceResolver {
      private String basePath;
  
      public ResourceResolver( String baseDirectory ){
          basePath = baseDirectory;
          if( !basePath.endsWith("/")){
              basePath += "/";
          }
      }
  
      @Override
      public LSInput resolveResource(String type, String namespaceURI, String publicId, String systemId, String baseURI) {
          System.out.println("Resolving: " + type + ", " + namespaceURI + ", " +  publicId  + ", " + systemId + ", " + baseURI + " (basepath:" + basePath + ")");
          String mypath = basePath + systemId;
          InputStream resourceAsStream = getClass().getResourceAsStream(mypath);
          if( resourceAsStream == null){ System.out.println("Ups! Stream is null"); }
  
          String contents = null;
          byte[] bytes = null;
          try {
              bytes = new byte[resourceAsStream.available()];
              resourceAsStream.read(bytes);
              contents = new String(bytes, Charset.forName("UTF-8"));
          } catch (IOException e) { } 
          finally{
              try { resourceAsStream.close(); } 
              catch (IOException e) { }
          }
          Input xmlInput = new Input(resourceAsStream, type, namespaceURI, publicId, systemId, basePath);    
          xmlInput.setStringData(contents);  // avoid problems with inputstream position
          return xmlInput;
      }
  }
  </code></pre>
  
  <p>And my ResourceResolver is used this way:</p>
  
  <pre><code>public boolean validate(Document doc, String xsdPath) throws SAXException, IOException, ParserConfigurationException {
      SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
      String rootElmtName = doc.getDocumentElement().getLocalName();
      String resourcePath = "/com/example/xml/" + xsdPath ;
      InputStream topSchema = getClass().getResourceAsStream(xsdPath + "/" + rootElmtName + ".xsd");
      Source schemaSource = new StreamSource(topSchema);
      ResourceResolver resolver = new ResourceResolver(resourcePath);
      schemaFactory.setResourceResolver(resolver);
      Schema schema = schemaFactory.newSchema(schemaSource);
      Validator validator = schema.newValidator();
      validator.setResourceResolver(resolver);
      Source source = new DOMSource(doc);
  
      ValidationErrorHandler handler = new ValidationErrorHandler();
      validator.setErrorHandler(handler);
      validator.validate(source);
      if(handler.hasErrors()){
          for( ValidationError e : handler.getErrors()){
              log(e);
          }
          return false;
      }
      return true;
  }
  </code></pre>
  
  <p>However, it doesn't work!
  It resolves a few schema resources and then stops 
  I tried setting a breakpoint in Eclipse in my resource resolver, and the inputstream is not null - it points to the right file containing a XSD. So something in the Java XML parser classes must expect some other behavior from my resolver.</p>
  
  <pre><code>Resolving: http://www.w3.org/2001/XMLSchema, http://com/example/xml/schemas/2005/08/07/, null, Letters.xsd, file:///com/example/xml/Schemas/2005/08/07/Message.xsd (basepath:/com/example/xml/Schemas/2005/08/07/)
  Resolving: http://www.w3.org/2001/XMLSchema, http://com/example/xml/schemas/2005/08/07/, null, GeneralElements.xsd, file:///com/example/xml/Schemas/2005/08/07/Message.xsd (basepath:/com/example/xml/Schemas/2005/08/07/)
  Resolving: http://www.w3.org/2001/XMLSchema, http://com/example/xml/schemas/2005/08/07/, null, GeneralTypes.xsd, file:///com/example/xml/Schemas/2005/08/07/Message.xsd (basepath:/com/example/xml/Schemas/2005/08/07/)
  Exception in thread "main" org.xml.sax.SAXParseException: src-resolve: Cannot resolve the name 'Letters' to a(n) 'group' component.
      at com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.createSAXParseException(ErrorHandlerWrapper.java:195)
      at com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.error(ErrorHandlerWrapper.java:131)
      at com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(XMLErrorReporter.java:384)
      at com.sun.org.apache.xerces.internal.impl.xs.traversers.XSDHandler.reportSchemaErr(XSDHandler.java:2537)
      at com.sun.org.apache.xerces.internal.impl.xs.traversers.XSDHandler.reportSchemaError(XSDHandler.java:2528)
      at com.sun.org.apache.xerces.internal.impl.xs.traversers.XSDHandler.getGlobalDecl(XSDHandler.java:1472)
      at com.sun.org.apache.xerces.internal.impl.xs.traversers.XSDGroupTraverser.traverseLocal(XSDGroupTraverser.java:72)
  </code></pre>
  
  <p>The contents of the Message.xsd contains a bit like this:</p>
  
  <pre><code>&lt;xs:include schemaLocation="Letters.xsd"/&gt;
  &lt;xs:include schemaLocation="GeneralElements.xsd"/&gt;
  &lt;xs:include schemaLocation="GeneralTypes.xsd"/&gt;
  &lt;xs:element name="Message"&gt; 
  </code></pre>
  
  <p>-and the Letters.xsd also contains </p>
  
  <pre><code>&lt;xs:include schemaLocation="GeneralElements.xsd"/&gt;
  &lt;xs:include schemaLocation="GeneralTypes.xsd"/&gt;
  &lt;xs:group name="Letters"&gt;
  </code></pre>
  
  <p>The outline is of the ResourceResolver and Input classes are from another SO post - so I might have misunderstood something.</p>
  
  <p>Is it the proper way I have created the resource resolver, or have I missed something completely?</p>