2010-08-24 15 views
5

Utilizando la última JAXB (Sun) y tienen una jerarquía de esquemas que usan directivas de importación entre esquemas para compartir definiciones de tipo. La validación del esquema se activa en la llamada setSchema a Marshaller/Unmarshaller en JAXB, que debe diferir la validación a Xerces (utilizando Java 1.5). No deseo saber el orden de las directivas de importación entre esquemas al crear el objeto Schema con SchemaFactory. Desafortunadamente, no he encontrado una característica/propiedad Xerces que permita esto. Por ejemplo, si se tira en a.xsd b.xsd con una importación a continuación, el código siguiente no funciona:JAXB ¿El orden de origen de SchemaFactory debe seguir el orden de importación entre esquemas?

FileInputStream a = new FileInputStream("a.xsd"); 
FileInputStream b = new FileInputStream("b.xsd"); 

Schema schema = SchemaFactory.newInstance(
    XMLConstants.W3C_XML_SCHEMA_NS_URI).newSchema(
     new Source[] { 
      new StreamSource(b), 
      new StreamSource(a) 
     } 
    ); 

El orden de la matriz de origen tiene que ser A.xsd continuación B.xsd. De cualquier forma alrededor de esto?

Respuesta

4

¿Qué sucede si crea un esquema en el Origen raíz y luego establece un ResourceResolver (LSResourceResolver) para resolver los otros esquemas importados durante la creación del esquema?

+0

Idea interesante. Puede que no siempre sepas el alcance de la jerarquía de esquemas. Así que no conozco todas las fuentes de raíz (básicamente coloco las gramáticas capturadas por el proceso XJC en un archivo META-INF, para catalogar, más los archivos de esquema reales en un contenedor y cargar SchemaFactory en tiempo de ejecución). Necesitaría una forma de asignar los espacios de nombres de las fuentes raíz a sus esquemas asociados. ¿Realmente no hay otra manera de dirigir Xerces para resolver la inclusión después de cargar todos los esquemas? –

+0

Eso aún puede ser posible, ojala alguien más ofrezca esa respuesta. El enfoque que sugerí permite a SchemaFactory dirigir el orden en que se resuelve el esquema sin tener que hacer el pedido. Usted especifica el esquema raíz, y pedirá nuevos a medida que se procesen las importaciones. –

+0

No he codificado todo el camino, solo he hecho una prueba rápida, pero su idea debería funcionar perfectamente ... más fácil con JRE 1.6, ya que hay más implementaciones de xerces instaladas. Publicaré mi código cuando tenga un ejemplo de trabajo. Gracias por señalarme en la dirección correcta. –

2

Publicación tardía del código.

generar un esquema de validación con:

SchemaFactory factory = SchemaFactory 
.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); 
factory.setResourceResolver(new SimpleResolver(streams)); 
.... 
Schema schemaGrammers = factory.newSchema(streams.toArray(new SchemaSource[0])); 

el esquema (schemaGrammers Object) Obtiene inyecta en el Marshaller:

Marshaller m = ...createMarshaller(); 
m.setSchema(<schemaGrammers>); 

Y el SimpleResolver implementa la clase LSResourceResolver:

private class SimpleResolver implements LSResourceResolver { 

    private Set<Source> streams; 

    public SimpleResolver(Set<Source> streams) { 
     this.streams = streams; 
    } 

    @Override 
    public LSInput resolveResource(String type, String namespaceURI, 
      String publicId, String systemId, String baseURI) { 
     DOMImplementationRegistry registry; 
     try { 

      registry = DOMImplementationRegistry.newInstance(); 
      DOMImplementationLS domImplementationLS = (DOMImplementationLS) registry 
        .getDOMImplementation("LS 3.0"); 

      LSInput ret = domImplementationLS.createLSInput(); 

      for (Source source : streams) { 
       SchemaSource schema = (SchemaSource) source; 
       if (schema.getResourceName().equals(
         schema.getResourceName(systemId)) 
         & schema.getTargetNamespace().equals(namespaceURI)) { 
        logger.debug(
          "Resolved systemid [{}] with namespace [{}]", 
          schema.getResourceName(systemId), namespaceURI); 

        URL url = new URL(schema.getSystemId()); 
        URLConnection uc = url.openConnection(); 

        ret.setByteStream(uc.getInputStream()); 
        ret.setSystemId(systemId); 
        return ret; 
       } 
      } 

     } catch (ClassCastException e) { 
      logger.error(e.getMessage()); 
     } catch (ClassNotFoundException e) { 
      logger.error(e.getMessage()); 
     } catch (InstantiationException e) { 
      logger.error(e.getMessage()); 
     } catch (IllegalAccessException e) { 
      logger.error(e.getMessage()); 
     } catch (FileNotFoundException e) { 
      logger.error(e.getMessage()); 
     } catch (IOException e) { 
      logger.error(e.getMessage()); 
     } 

     logger.error("No stream found for system id [{}]", systemId); 
     return null; 
    } 

} 

Se debe crear una nueva corriente de entrada; de lo contrario, se produce un conflicto. No estoy seguro de por qué (no se molestó en depurar el código) sino de las transmisiones que paso al constructor [es decir. el objeto Set] ya han sido leídos.

Cuestiones relacionadas