Impresionante salida de javax.xml.transform.Transformer con solo api java estándar (sangría y posicionamiento de Doctype)

Usando el siguiente código simple:

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( "")); 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()); } } 

Obtengo el resultado:

       

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 Cómo imprimir bastante xml desde Java , sin embargo , casi todas las respuestas en esa pregunta dependen de 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 tienes 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.

La parte faltante es la cantidad para sangrar. Puede establecer la sangría y el sangría de la siguiente manera:

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

Una pequeña clase de utilidades como 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 es provisto por xercesImpl de Apache Foundation . Aquí está la dependencia maven:

  xerces xercesImpl 2.11.0  

Puede encontrar la dependencia de su herramienta de comstackción favorita aquí: http://mvnrepository.com/artifact/xerces/xercesImpl/2.11.0 .

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

Para hacer 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.