2009-01-14 16 views
21

Estoy utilizando JAXP para generar y analizar un documento XML desde el que se cargan algunos campos desde una base de datos.Producción de XML válido con codificación Java y UTF-8

Código para serializar el XML:

DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); 
Document doc = builder.newDocument(); 
Element root = doc.createElement("test"); 
root.setAttribute("version", text); 
doc.appendChild(root); 

DOMSource domSource = new DOMSource(doc); 
TransformerFactory tFactory = TransformerFactory.newInstance(); 

FileWriter out = new FileWriter("test.xml"); 
Transformer transformer = tFactory.newTransformer(); 
transformer.setOutputProperty(OutputKeys.INDENT, "yes"); 
transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8"); 
transformer.transform(domSource, new StreamResult(out)); 

código para analizar el código XML:

DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); 
factory.setNamespaceAware(true); 
DocumentBuilder builder = factory.newDocumentBuilder(); 
Document doc = builder.parse("test.xml"); 

Y me encuentro con la siguiente excepción:

[Fatal Error] test.xml:1:4: Invalid byte 1 of 1-byte UTF-8 sequence. 
Exception in thread "main" org.xml.sax.SAXParseException: Invalid byte 1 of 1-byte UTF-8 sequence. 
    at org.apache.xerces.parsers.DOMParser.parse(Unknown Source) 
    at org.apache.xerces.jaxp.DocumentBuilderImpl.parse(Unknown Source) 
    at javax.xml.parsers.DocumentBuilder.parse(Unknown Source) 
    at com.test.Test.xml(Test.java:27) 
    at com.test.Test.main(Test.java:55) 

El texto cadena incluye u- umlaut y o-umlaut (códigos de caracteres 0xFC y 0xF6). Estos son los personajes que están causando el error. Cuando escapo de String para usar & #xFC; y & # xF6; entonces el problema desaparece Otras entidades se codifican automáticamente cuando escribo el XML.

¿Cómo consigo que mi salida se escriba/lea correctamente sin sustituir estos caracteres por mí mismo?

(He leído las siguientes preguntas ya:

How to encode characters from Oracle to XML?

Repairing wrong encoding in XML files)

Respuesta

31

Utilice un FileOutputStream en lugar de un FileWriter.

Este último aplica su propia codificación, que es casi seguro que no es UTF-8 (dependiendo de su plataforma, es probable que sea Windows-1252 o IS-8859-1).

Editar (ahora que tengo algo de tiempo):

se permite un documento XML sin un prólogo a ser codificado como UTF-8 o UTF-16. Con un prólogo, se permite especificar su codificación (el prólogo puede contener solo caracteres US-ASCII, por lo que el prólogo siempre es legible).

Un lector se ocupa de los caracteres; Decodificará la secuencia de bytes del InputStream subyacente. Como resultado, cuando pasa un lector al analizador, le dice que ya ha manejado la codificación, por lo que el analizador ignorará el prólogo. Cuando pasa un InputStream (que lee bytes), no hace esta suposición, y buscará en el prólogo para definir la codificación, o por defecto a UTF-8/UTF-16 si no está allí.

Nunca he intentado leer un archivo codificado en UTF-16. Sospecho que el analizador buscará una Marca de Orden de Byte (BOM) como los primeros 2 bytes del archivo.

+0

Agradable y fácil, pensé en cambiar a esto pero descarté la idea ya que no vi una forma de especificar la codificación en el constructor. Funcionó bien, gracias. –

+0

Me pegué un tiro en el pie con FileWriter una vez ... +1 –

+0

Excelente respuesta: ¡de ahora en adelante buscaré Gotchas escondidas en FileWriter! –

5

Bueno, con seguridad 0xFC y 0xF6 no son válidos UTF-8 caracteres. Estos deberían haber finalizado en las dos secuencias de bytes: 0x3CBC y 0x3CB6.

Lo más probable es que el problema se deba a que la fuente original de los caracteres se define como UTF-8 cuando no lo están.

+0

Al cambiar el FileWriter a FileOutputStream, de hecho, estos caracteres se codificaron con dos secuencias de bytes: 0xC3BC y 0xC3B6. –