2011-12-12 55 views
5

Creo una cadena XML sobre la marcha (NO leyendo desde un archivo). Luego uso Cocoon 3 para transformarlo a través de FOP a PDF. En algún lugar en el medio se ejecuta Xerces. Cuando uso las cosas codificadas, todo funciona. Tan pronto como pongo una diéresis alemán en la base de datos y enriquecer mi xml con esos datos me sale:Tengo UTF-8, pero aún obtengo "Byte no válido 1 de 1 byte secuencia UTF-8"

Caused by: org.apache.cocoon.pipeline.ProcessingException: Can't parse the XML string. 
at org.apache.cocoon.sax.component.XMLGenerator$StringGenerator.execute(XMLGenerator.java:326) 
at org.apache.cocoon.sax.component.XMLGenerator.execute(XMLGenerator.java:104) 
at org.apache.cocoon.pipeline.AbstractPipeline.invokeStarter(AbstractPipeline.java:146) 
at org.apache.cocoon.pipeline.AbstractPipeline.execute(AbstractPipeline.java:76) 
at de.grobmeier.tab.webapp.modules.documents.InvoicePipeline.generateInvoice(InvoicePipeline.java:74) 
... 87 more 

Caused by: com.sun.org.apache.xerces.internal.impl.io.MalformedByteSequenceException: Invalid byte 1 of 1-byte UTF-8 sequence. 
    at com.sun.org.apache.xerces.internal.impl.io.UTF8Reader.invalidByte(UTF8Reader.java:684) 
    at com.sun.org.apache.xerces.internal.impl.io.UTF8Reader.read(UTF8Reader.java:554) 

Entonces he depurado mi aplicación y descubierto, mi "A" (que viene frome la base de datos) tiene el valor de byte de 196, que es C4 en hex. Esto es lo que esperaba de acuerdo con esto: http://www.utf8-zeichentabelle.de/

No sé por qué mi código falla.

entonces han tratado de añadir manualmente una lista de materiales, así:

byte[] bom = new byte[3]; 
bom[0] = (byte) 0xEF; 
bom[1] = (byte) 0xBB; 
bom[2] = (byte) 0xBF; 
String myString = new String(bom) + inputString; 

Sé que esto no es exactamente bueno, pero que lo probamos - por supuesto que no. He intentado añadir una cabecera XML delante:

<?xml version="1.0" encoding="UTF-8"?> 

que fracasó también. Luego lo combiné. Ha fallado.

Después de todo he intentado algo así:

xmlInput = new String(xmlInput.getBytes("UTF8"), "UTF8"); 

¿Qué está haciendo nada, de hecho, porque ya es UTF-8. Todavía falla.

Entonces ... ¿Alguna idea de lo que estoy haciendo mal y de lo que Xerces espera de mí?

Gracias Cristiano

+0

Estoy de acuerdo, pero no me ayuda. Porque la Cadena problemática que proviene de la base de datos se crea desde mi capa ORM. Además, tiene 0xC4 que debería estar bien, ¿verdad? – Christian

+0

Uso MySQL, la tabla y las columnas están codificadas con utf8_general_ci. He agregado useUnicode = true y characterEncoding = utf8 a mi conexión jdbc. – Christian

+0

Puede que no sea una buena idea especificar esos parámetros en la conexión JDBC cuando te conectas a un DB con una codificación diferente; solo úsala cuando la autodetección no funcione. ¿Qué usas para escribir los datos, y es esto una columna BLOB o VARCHAR? – JBert

Respuesta

12

Si su base de datos contiene solo un byte (con valor 0xC4), entonces no está utilizando la codificación UTF-8.

El carácter "LETRA MAYÚSCULA LATINA A CON DIAESIS" tiene un valor de punto de código U + 00C4, pero UTF-8 no puede codificar eso en un solo byte. Si marca la tercera columna "UTF-8 (hex.)" En UTF8-zeichentabelle.de, verá que UTF-8 lo codifica como 0xC3 84 (dos bytes).

Lea el artículo de Joel "The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!)" para obtener más información.


EDIT: Christian encontró la respuesta a sí mismo; Resultó que era un problema en el componente Cocoon 3 SAX (supongo que es la versión alfa 3). Resulta que si pasa un XML como una cadena a la clase XMLGenerator, algo saldrá mal durante el análisis SAX causando este desastre.

I looked up the code para encontrar el problema real en el capullo-stax:

if (XMLGenerator.this.logger.isDebugEnabled()) { 
    XMLGenerator.this.logger.debug("Using a string to produce SAX events."); 
} 
XMLUtils.toSax(new ByteArrayInputStream(this.xmlString.getBytes()), XMLGenerator.this.getSAXConsumer(); 

Como se puede ver, la llamada getBytes() creará una matriz de bytes con la codificación por defecto del JRE que a su vez dejar de analizar. Esto se debe a que el XML se declara como UTF-8, mientras que los datos ahora están en bytes otra vez, y es probable que use su página de códigos de Windows.

Como solución alternativa, se puede utilizar el siguiente:

new org.apache.cocoon.sax.component.XMLGenerator(xmlInput.getBytes("UTF-8"), 
     "UTF-8"); 

Esto hará que las acciones internas derecha (como Cristiano averiguó mediante la experimentación con la API).

Tengo opened an issue en el rastreador de errores de Apache.

EDIT 2: se corrigió el problema y se incluirá en una próxima versión.

+0

¡Un camino para ir más allá! – Pops

2

El C4 que se ve en esa página se refiere al punto de código Unicode, U+00C4. La secuencia de bytes utilizada para representar dicho punto de código en UTF-8 NO es "\xC4". Lo que quiere es lo que está en la columna UTF-8 (hex.), Es decir, "\xC3\x84".

Por lo tanto, sus datos no están en UTF-8.

Puede leer sobre cómo se codifican los datos en UTF-8 here.

0

Estoy ejecutando Windows 7 con TextPad como editor de texto para compilar manualmente el archivo de datos xml. Obtuve el MalformedByteSequenceException. Mi especificación en el archivo xml fue UTF-8. Después de hurgar, encontré que mi editor tenía una herramienta "Herramientas ... Convertir a DOS". Lo hice, volví a guardar el archivo y la excepción desapareció y mi código funcionó bien.

Luego busqué la codificación predeterminada para ese tipo de archivo en mi editor. Era ASCII, aunque cuando cambié el parámetro de codificación xml a ASCII, obtuve otro MalformedByteSequenceException diferente.

Así que en los sistemas Windows, puede intentar mantener la codificación xml en UTF-8, pero guarde el archivo codificado en DOS. No profundicé más sobre por qué funciona esto.

Cuestiones relacionadas