xml serialization - ¿Es posible personalizar el prefijo de espacio de nombres que JAXB utiliza cuando se está formando a una cadena?
xml-serialization java-metro-framework (4)
Hay una forma de hacer esto, que utiliza una clase de implementación JAXB interna 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, en la que puede crear subclases e implementar el método abstracto que asigna URI de espacio de nombres a prefijos.
A continuación, 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 entiendes la idea.
Tenga en cuenta que esta es una clase de implementación JAXB interna, por lo que no hay garantía de que esté allí en futuras versiones.
Por ejemplo, tengo un esquema simple que importa otro esquema. El segundo esquema (urn: just: attributes, just-attributes.xsd) simplemente define un grupo de atributos.
<?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 usando la tarea Metro xjc Ant para generar clases fuera de este esquema. El problema que estoy encontrando es que la aplicación de terceros con la que estoy interactuando es peculiar sobre los espacios de nombres. Este caso necesito un valor de cadena, por lo que tengo que serializarlo. Yo uso el 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 este tercero espera algo como xmlns:thirdpartyns="urn:just:attributes"
, es decir, se analizan en función del nombre asignado al espacio de nombres. Tiene que ser "thirdpartyns" para que su software funcione.
¿Alguien sabe de una manera de evitar esto, a no ser que encuentre y reemplace la cadena resultante? Una regla de enlace personalizado tal vez?
Lo probé en Java SE6 y requiere un pequeño cambio en comparación con la solución para Java SE 5 (como se describe that ):
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 .internal.
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 a 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 los atributos del espacio de nombres predeterminado (en este caso, crea un nuevo espacio de nombres llamado ns1)
Tenía la misma pregunta. En package-info.java
(si no lo tiene, simplemente puede crearlo manualmente) agregue 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)
http://hwellmann.blogspot.com/2011/03/jaxb-marshalling-with-custom-namespace.html
Esto muestra cómo hacerlo.
Otro: http://www.systemmobile.com/?p=280
Bits clave en caso de que el enlace muera también:
la clase NamespacePrefixMapper, que se encuentra en el paquete com.sun.xml.bind.marshaller. La clase abstracta tiene un método para implementar:
public abstract String getPreferredPrefix(
String namespaceUri,
String suggestion,
boolean requirePrefix);
entonces
Marshaller marshaller =
jaxbContext.createMarshaller();
marshaller.setProperty(”com.sun.xml.bind.namespacePrefixMapper”,
new MyNamespacePrefixMapper());
Si también está utilizando javax.xml.xpath.XPath, NamespacePrefixMapper también puede implementar javax.xml.namespace.NamespaceContext, centralizando la personalización de su espacio de nombres en una sola clase.