2009-12-30 16 views
22

Por ejemplo, tengo un esquema simple que importa otro esquema. El segundo esquema (urn: just: attributes, just-attributes.xsd) solo define un grupo de atributos.¿Es posible personalizar el prefijo del espacio de nombres que utiliza JAXB cuando se coordina con una Cadena?

<?xml version="1.0" encoding="UTF-8"?> 
<schema xmlns="http://www.w3.org/2001/XMLSchema" 
    targetNamespace="http://www.example.org/MySchema" 
    xmlns:tns="http://www.example.org/MySchema" 
    elementFormDefault="qualified" 
    xmlns:ja="urn:just:attributes"> 

    <import schemaLocation="just-attributes.xsd" namespace="urn:just:attributes"/> 

    <element name="MyElement"> 
     <complexType> 
      <attributeGroup ref="ja:AttributeGroup"/> 
     </complexType> 
    </element> 
</schema> 

Estoy utilizando la tarea Metro xjc Ant para generar clases fuera de este esquema. El problema al que me estoy enfrentando es que la aplicación de terceros con la que estoy interactuando es peculiar sobre los espacios de nombres. En este caso, necesito un valor de cadena, así que tengo que serializarlo. Yo uso un código repetitivo para esto.

private static <T> String marshal(T object) throws JAXBException{ 
    OutputStream outputStream = new ByteArrayOutputStream(); 
    JAXBContext jaxbContext = JAXBContext.newInstance(object.getClass()); 
    Marshaller marshaller = jaxbContext.createMarshaller(); 
    marshaller.marshal(object, outputStream); 
    return outputStream.toString(); 
} 

Lo que me da algo en la línea de

<?xml version="1.0" encoding="UTF-8" standalone="yes"?> 
<ns2:MyElement xmlns:ns1="urn:just:attributes" xmlns:ns2="http://www.example.org/MySchema" ns1:attrib1="1234" ns1:attrib2="5678"/> 

El problema que tengo es que esta tercera parte espera algo así como xmlns:thirdpartyns="urn:just:attributes", es decir, que se está analizando en función del nombredado al espacio de nombres. Es tiene para ser "thirdpartyns" para que su software funcione.

¿Alguien sabe de una forma de evitar esto, a menos de hacer un hallazgo y reemplazar en la cadena resultante? Una regla de enlace personalizado tal vez?

Respuesta

26

http://hwellmann.blogspot.com/2011/03/jaxb-marshalling-with-custom-namespace.html

Esto muestra cómo hacerlo.

Otra: http://www.systemmobile.com/?p=280

bits de la clave en caso de que vincular también muere:

la clase NamespacePrefixMapper, que se encuentra en el paquete com.sun.xml.bind.marshaller. La clase abstracta tiene un método para poner en práctica:

public abstract String getPreferredPrefix( 
    String namespaceUri,   
    String suggestion,   
    boolean requirePrefix); 

continuación

Marshaller marshaller =   
    jaxbContext.createMarshaller();   
marshaller.setProperty(”com.sun.xml.bind.namespacePrefixMapper”,   
    new MyNamespacePrefixMapper()); 

Si también está utilizando javax.xml.xpath.XPath, su NamespacePrefixMapper también puede implementar javax.xml.namespace.NamespaceContext , centralizando su personalización del espacio de nombres en una sola clase.

+0

Gracias. Esto funciona como un encanto! –

+0

El enlace está roto. –

+0

El enlace está muerto ... @DaveC por favor ¡compruébalo! – basZero

0

Hay una forma de hacerlo, que utiliza una clase de implementación interna de JAXB llamada NamespacePrefixMapper. En JAXB RI, esto está en com.sun.xml.bind.marshaller, pero en Java6, está en com.sun.xml.internal.bind.marshaller.

Esta es una clase abstracta, que puede crear una subclase e implementar el método abstracto que correlaciona los URI de espacio de nombres con los prefijos.

A continuación, se inyecta una instancia de esa subclase en el contador de referencias:

JAXBContext context = ... 
Marshaller marshaller = context.createMarshaller(); 
NamespacePrefixMapper prefixMapper = new MyPrefixMapperImpl(); 
marshaller.setProperty("com.sun.xml.bind.namespacePrefixMapper", prefixMapper); 

El nombre de la propiedad va a ser diferente para la versión java6, pero se entiende la idea.

Tenga en cuenta que esta es una clase de implementación JAXB interna, por lo que no hay garantía de que estará allí en versiones futuras.

+1

Por favor, no subclass la clase 'internal'. – Barett

11

He probado that en Java SE6 y requiere un pequeño cambio en comparación con la solución para Java SE 5 (como se describe above):

Marshaller m = context.createMarshaller(); 
    m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE); 
    m.setProperty(Marshaller.JAXB_ENCODING, "UTF-8"); 
    m.setProperty("com.sun.xml.internal.bind.namespacePrefixMapper", mapper); 

Así que la tercera propiedad de arriba contiene el .internal. adicional en el nombre del paquete en comparación con la versión de Java SE5. Lo que no descubrí aún es cómo decirle al Marshaller qué URI de espacio de nombres se convierte en el espacio de nombres predeterminado (""). Si anulo el método getPreferredPrefix() y devuelvo una cadena vacía, el Marshaller tiene problemas con la escritura de atributos del espacio de nombres predeterminado (en este caso crea un nuevo espacio de nombres llamado ns1)

+2

Aparentemente en java SE 7, usa nuevamente "com.sun.xml.bind.namespacePrefixMapper" .... (con la propiedad Java SE 6 obtengo una excepción) – edbras

+2

¿Alguien sabe cómo sería correcto para Java SE? 8? @edbras – basZero

5

Tenía la misma pregunta. En package-info.java (si no lo tiene, sólo puede crear manualmente) añadir la parte xmlns:

@javax.xml.bind.annotation.XmlSchema(xmlns = { 
     @javax.xml.bind.annotation.XmlNs(namespaceURI = "urn:just:attributes", prefix = "thirdpartyns") }, 
     elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED) 
+1

¿Qué sucede si genero fuentes de xsd? Usando apache plugin maven. ¿Cómo puedo personalizarlo de esta manera? –

Cuestiones relacionadas