¿Puedo forzar a JAXB a no convertir “en & quot ;, por ejemplo, al organizar en XML?

Tengo un Objeto que se dirige a XML usando JAXB. Un elemento contiene una cadena que incluye comillas (“). El XML resultante tiene " donde” existía “.

Aunque esto normalmente se prefiere, necesito que mi salida coincida con un sistema heredado . ¿Cómo obligo a JAXB a NO convertir las entidades HTML?

Gracias por las respuestas Sin embargo, nunca veo el controlador llamado escape (). ¿Puedes echar un vistazo y ver qué estoy haciendo mal? ¡Gracias!

 package org.dc.model; import java.io.IOException; import java.io.Writer; import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBException; import javax.xml.bind.Marshaller; import org.dc.generated.Shiporder; import com.sun.xml.internal.bind.marshaller.CharacterEscapeHandler; public class PleaseWork { public void prettyPlease() throws JAXBException { Shiporder shipOrder = new Shiporder(); shipOrder.setOrderid("Order's ID"); shipOrder.setOrderperson("The woman said, \"How ya doin & stuff?\""); JAXBContext context = JAXBContext.newInstance("org.dc.generated"); Marshaller marshaller = context.createMarshaller(); marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE); marshaller.setProperty(CharacterEscapeHandler.class.getName(), new CharacterEscapeHandler() { @Override public void escape(char[] ch, int start, int length, boolean isAttVal, Writer out) throws IOException { out.write("Called escape for characters = " + ch.toString()); } }); marshaller.marshal(shipOrder, System.out); } public static void main(String[] args) throws Exception { new PleaseWork().prettyPlease(); } } 

El resultado es esto:

   The woman said, "How ya doin & stuff?"  

y como puede ver, la callback nunca se muestra. (Una vez que reciba la callback, me preocuparé por hacer que realmente haga lo que quiero).

Solución que mi compañero de equipo encontró:

 PrintWriter printWriter = new PrintWriter(new FileWriter(xmlFile)); DataWriter dataWriter = new DataWriter(printWriter, "UTF-8", DumbEscapeHandler.theInstance); marshaller.marshal(request, dataWriter); 

En lugar de pasar el xmlFile a mariscal (), pase el DataWriter que conoce tanto la encoding como un manejador de escape apropiado, si lo hay.

Nota: Dado que DataWriter y DumbEscapeHandler están dentro del paquete com.sun.xml.internal.bind.marshaller, debe iniciar bootstrap javac.

Acabo de crear mi controlador personalizado como una clase como esta:

 import java.io.IOException; import java.io.StringWriter; import java.io.Writer; import com.sun.xml.bind.marshaller.CharacterEscapeHandler; public class XmlCharacterHandler implements CharacterEscapeHandler { public void escape(char[] buf, int start, int len, boolean isAttValue, Writer out) throws IOException { StringWriter buffer = new StringWriter(); for (int i = start; i < start + len; i++) { buffer.write(buf[i]); } String st = buffer.toString(); if (!st.contains("CDATA")) { st = buffer.toString().replace("&", "&").replace("<", "<") .replace(">", ">").replace("'", "'") .replace("\"", """); } out.write(st); System.out.println(st); } } 

en el método Marshaller, simplemente llame a:

 marshaller.setProperty(CharacterEscapeHandler.class.getName(), new XmlCharacterHandler()); 

funciona bien.

He estado jugando con tu ejemplo un poco y depurando el código JAXB. Y parece que es algo específico sobre la encoding UTF-8 utilizada. La propiedad escapeHandler de MarshallerImpl parece estar configurada correctamente. Sin embargo, se está utilizando no en todos los contextos. Si busqué las llamadas de MarshallerImpl.createEscapeHandler() encontré:

 public XmlOutput createWriter( OutputStream os, String encoding ) throws JAXBException { // UTF8XmlOutput does buffering on its own, and // otherwise createWriter(Writer) inserts a buffering, // so no point in doing a buffering here. if(encoding.equals("UTF-8")) { Encoded[] table = context.getUTF8NameTable(); final UTF8XmlOutput out; if(isFormattedOutput()) out = new IndentingUTF8XmlOutput(os,indent,table); else { if(c14nSupport) out = new C14nXmlOutput(os,table,context.c14nSupport); else out = new UTF8XmlOutput(os,table); } if(header!=null) out.setHeader(header); return out; } try { return createWriter( new OutputStreamWriter(os,getJavaEncoding(encoding)), encoding ); } catch( UnsupportedEncodingException e ) { throw new MarshalException( Messages.UNSUPPORTED_ENCODING.format(encoding), e ); } } 

Tenga en cuenta que en su configuración se toma en consideración la sección superior (...equals("UTF-8")...) . Sin embargo, este no toma el escapeHandler . Sin embargo, si configuras la encoding en cualquier otra, se llama a la parte inferior de este método ( createWriter(OutputStream, String) ) y este usa escapeHandler , por lo que EH cumple su función. Entonces, agregando …

  marshaller.setProperty(Marshaller.JAXB_ENCODING, "ASCII"); 

hace que se llame a su CharacterEscapeHandler personalizado. No estoy seguro, pero creo que esto es una especie de error en JAXB.

@ Elliot puede usar esto para permitir que Marshaller ingrese la función characterEscape. Es extraño pero funciona si configura ” Unicode ” en lugar de “UTF-8”. Agregue esto justo antes o después de establecer la propiedad CharacterEscapeHandler.

 marshaller.setProperty(Marshaller.JAXB_ENCODING, "Unicode"); 

Sin embargo , no se asegure solo de verificar su consola dentro de su IDE, ya que debe mostrarse de acuerdo con la encoding del área de trabajo. Es mejor verificarlo también desde un archivo como ese:

 marshaller.marshal(shipOrder, new File("C:\\shipOrder.txt")); 

Diría que la forma más fácil de hacerlo es anulando CharacterEscapeHandler :

 marshaller.setProperty("com.sun.xml.bind.characterEscapeHandler", new CharacterEscapeHandler() { @Override public void escape(char[] ch, int start, int length, boolean isAttVal, Writer out) throws IOException { out.write(ch, start, length); } }); 

Parece que es posible con la implementación de JAXB de Sun , aunque no lo hice yo mismo.

Revisé la especificación XML. http://www.w3.org/TR/REC-xml/#sec-references dice “los documentos bien formados no necesitan declarar ninguna de las siguientes entidades: amp, lt, gt, apos, quot.” por lo que parece que el analizador XML utilizado por el sistema heredado no es conforme.

(Sé que no resuelve tu problema, pero al menos es bueno poder decir qué componente está roto).

Esto funciona para mí después de leer otras publicaciones:

 javax.xml.bind.JAXBContext jc = javax.xml.bind.JAXBContext.newInstance(object); marshaller = jc.createMarshaller(); marshaller.setProperty(javax.xml.bind.Marshaller.JAXB_FORMATTED_OUTPUT, true); marshaller.setProperty(javax.xml.bind.Marshaller.JAXB_ENCODING, "UTF-8"); marshaller.setProperty(CharacterEscapeHandler.class.getName(), new CustomCharacterEscapeHandler()); public static class CustomCharacterEscapeHandler implements CharacterEscapeHandler { /** * Escape characters inside the buffer and send the output to the Writer. * (prevent  to be converted <b> but still ok for a<5.) */ public void escape(char[] buf, int start, int len, boolean isAttValue, Writer out) throws IOException { if (buf != null){ StringBuilder sb = new StringBuilder(); for (int i = start; i < start + len; i++) { char ch = buf[i]; //by adding these, it prevent the problem happened when unmarshalling if (ch == '&') { sb.append("&"); continue; } if (ch == '"' && isAttValue) { sb.append("""); continue; } if (ch == '\'' && isAttValue) { sb.append("'"); continue; } // otherwise print normally sb.append(ch); } //Make corrections of unintended changes String st = sb.toString(); st = st.replace("&quot;", """) .replace("&lt;", "<") .replace("&gt;", ">") .replace("&apos;", "'") .replace("&amp;", "&"); out.write(st); } } } 

interesante, pero con cuerdas puedes probar

 Marshaller marshaller = jaxbContext.createMarshaller(); StringWriter sw = new StringWriter(); marshaller.marshal(data, sw); sw.toString(); 

al menos para mí esto no escapa citas

La forma más simple, al utilizar la implementación de Marshaller de sun es proporcionar su propia implementación del CharacterEscapeEncoder que no escapa a nada.

  Marshaller m = jcb.createMarshaller(); m.setProperty( "com.sun.xml.bind.marshaller.CharacterEscapeHandler", new NullCharacterEscapeHandler()); 

Con

 public class NullCharacterEscapeHandler implements CharacterEscapeHandler { public NullCharacterEscapeHandler() { super(); } public void escape(char[] ch, int start, int length, boolean isAttVal, Writer writer) throws IOException { writer.write( ch, start, length ); } } 

Por alguna razón no tengo tiempo para averiguarlo, funcionó para mí cuando establecí

 marshaller.setProperty(Marshaller.JAXB_ENCODING, "utf-8"); 

A diferencia del uso de "UTF-8" o "Unicode"

Sugiero que los pruebes, y como dijo @Javatar , verifícalos arrojando al archivo usando:

 marshaller.marshal(shipOrder, new File("")); 

y abrirlo con un editor de texto decente como notepad ++

    Intereting Posts