2009-08-12 11 views
53

Usando el siguiente código simple:Pretty-impresión de salida de javax.xml.transform.Transformer con api único estándar java (sangría y posicionamiento Doctype)

package test; 

import java.io.*; 
import javax.xml.transform.*; 
import javax.xml.transform.stream.*; 

public class TestOutputKeys { 
    public static void main(String[] args) throws TransformerException { 

     // Instantiate transformer input 
     Source xmlInput = new StreamSource(new StringReader(
       "<!-- Document comment --><aaa><bbb/><ccc/></aaa>")); 
     StreamResult xmlOutput = new StreamResult(new StringWriter()); 

     // Configure transformer 
     Transformer transformer = TransformerFactory.newInstance() 
       .newTransformer(); // An identity transformer 
     transformer.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, "testing.dtd"); 
     transformer.setOutputProperty(OutputKeys.INDENT, "yes"); 
     transformer.transform(xmlInput, xmlOutput); 

     System.out.println(xmlOutput.getWriter().toString()); 
    } 

} 

consigo la salida:

<?xml version="1.0" encoding="UTF-8"?> 
<!-- Document comment --><!DOCTYPE aaa SYSTEM "testing.dtd"> 

<aaa> 
<bbb/> 
<ccc/> 
</aaa> 

Pregunta A: la etiqueta doctype aparece después del comentario del documento. ¿Es posible hacer que aparezca antes del comentario del documento?

Pregunta B: ¿Cómo logro la indentación, usando solo la API de JavaSE 5.0? Esta pregunta es esencialmente idéntica a How to pretty-print xml from java, , sin embargo, casi todas las respuestas en esa pregunta dependen de las bibliotecas externas. La única respuesta aplicable (publicada por un usuario llamado Lorenzo Boccaccia) que solo utiliza la API de Java, es básicamente igual al código publicado anteriormente, pero no funciona para mí (como se muestra en la salida, no recibo sangría).

Supongo que tiene que establecer la cantidad de espacios para usar para la sangría, como lo hacen muchas de las respuestas con bibliotecas externas, pero no puedo encontrar dónde especificar eso en la API de Java. Dado el hecho de que la posibilidad de establecer una propiedad de sangría a "sí" existe en la API java, debe ser posible realizar sangría de alguna manera. Simplemente no puedo entender cómo.

+0

La pregunta A no tiene sentido. ¿Te refieres a "antes" en la segunda parte? –

+0

Sí. Edité la pregunta para cambiar el error tipográfico. Gracias. – Alderath

+4

Repitiendo el comentario que hice en http://stackoverflow.com/questions/139076/how-to-pretty-print-xml-from-java - ahora puede imprimir bastante sin bibliotecas externas. Ver http://xerces.apache.org/xerces2-j/faq-general.html#faq-6. Sí, esta es una pregunta frecuente de Xerces, pero la respuesta abarca las clases estándar de JDK. La implementación 1.5 inicial de estas clases tenía muchos problemas, pero todo funciona bien desde 1.6 en adelante. Copie el ejemplo de LSSerializer en las preguntas frecuentes, corte el bit "..." y agregue 'writer.getDomConfig(). SetParameter (" format-pretty-print ", Boolean.TRUE);' después del 'LSSerializer writer = ... 'línea. –

Respuesta

106

La parte faltante es la cantidad de sangrado. Se puede establecer la sangría y la cantidad guión de la siguiente manera:

transformer.setOutputProperty(OutputKeys.INDENT, "yes"); 
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2"); 
transformer.transform(xmlInput, xmlOutput); 
+0

hmm acaba de probar esto con su muestra y obtuve un error –

+0

me funciona – dfa

+0

es bueno saberlo, creo que falló porque tenía una versión anterior de xalan, comprobación doble –

1

Probablemente se podría embellecer todo con un XSLT file. Google arroja algunos resultados, pero no puedo comentar sobre su corrección.

+0

Me gusta esta idea. Uso XSLT bastante para este tipo de cosas (maniuplación del espacio de nombres, control del espacio en blanco, etc.). No es eficiente, pero es bastante fácil y no depende del analizador. – skaffman

4

Un poco de clase util como un ejemplo ...

import org.apache.xml.serialize.XMLSerializer; 

public class XmlUtil { 

public static Document file2Document(File file) throws Exception { 
    if (file == null || !file.exists()) { 
     throw new IllegalArgumentException("File must exist![" + file == null ? "NULL" 
       : ("Could not be found: " + file.getAbsolutePath()) + "]"); 
    } 
    DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance(); 
    dbFactory.setNamespaceAware(true); 
    return dbFactory.newDocumentBuilder().parse(new FileInputStream(file)); 
} 

public static Document string2Document(String xml) throws Exception { 
    InputSource src = new InputSource(new StringReader(xml)); 
    DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance(); 
    dbFactory.setNamespaceAware(true); 
    return dbFactory.newDocumentBuilder().parse(src); 
} 

public static OutputFormat getPrettyPrintFormat() { 
    OutputFormat format = new OutputFormat(); 
    format.setLineWidth(120); 
    format.setIndenting(true); 
    format.setIndent(2); 
    format.setEncoding("UTF-8"); 
    return format; 
} 

public static String document2String(Document doc, OutputFormat format) throws Exception { 
    StringWriter stringOut = new StringWriter(); 
    XMLSerializer serial = new XMLSerializer(stringOut, format); 
    serial.serialize(doc); 
    return stringOut.toString(); 
} 

public static String document2String(Document doc) throws Exception { 
    return XmlUtil.document2String(doc, XmlUtil.getPrettyPrintFormat()); 
} 

public static void document2File(Document doc, File file) throws Exception { 
    XmlUtil.document2String(doc, XmlUtil.getPrettyPrintFormat()); 
} 

public static void document2File(Document doc, File file, OutputFormat format) throws Exception { 
    XMLSerializer serializer = new XMLSerializer(new FileOutputStream(file), format); 
    serializer.serialize(doc); 
} 
} 

XMLSerializer se proporciona por xeresImpl. Aquí está la dependencia Maven:

<dependency> 
    <groupId>xerces</groupId> 
    <artifactId>xercesImpl</artifactId> 
    <version>2.11.0</version> 
</dependency> 

puede encontrar la dependencia para su herramienta de construcción favorito aquí: http://mvnrepository.com/artifact/xerces/xercesImpl/2.11.0.

+0

Agregue las referencias a bibliotecas externas, por favor. Esta muestra no funciona solo con el JDK. XMLSerializer pertenece a org.apache.xml.serialize. – Aubin

0

Para que la salida sea un documento XML válido, NO. Un documento XML válido debe comenzar con una instrucción de procesamiento. Consulte la especificación XML http://www.w3.org/TR/REC-xml/#sec-prolog-dtd para obtener más detalles.

+0

Esta respuesta se basa en un malentendido de la pregunta. El comentario está permitido antes o después de la declaración del tipo de documento. Es decir. puede tener 'xmlDeclaration comment doctypeDeclaration' o' xmlDeclaration doctypeDeclaration comment'. La pregunta nunca habló sobre poner algo antes de la Declaración xml. – Alderath

+0

Sí, tienes razón. Estúpido yo... – Oskar

Cuestiones relacionadas