Tengo una cadena de Java que contiene XML, sin avances de línea ni sangrías. Me gustaría convertirlo en una cadena con XML bien formateado. ¿Cómo hago esto?
String unformattedXml = "<tag><nested>hello</nested></tag>";
String formattedXml = new [UnknownClass]().format(unformattedXml);
Nota: Mi entrada es una cadena . Mi salida es una cadena .
(Básico) resultado simulado:
<?xml version="1.0" encoding="UTF-8"?>
<root>
<tag>
<nested>hello</nested>
</tag>
</root>
java
xml
pretty-print
Steve McLeod
fuente
fuente
Respuestas:
Nota: Los resultados pueden variar según la versión de Java. Busque soluciones específicas para su plataforma.
fuente
<?xml version="1.0" encoding="UTF-8"?>
?<?xml ...>
declaración, agreguetransformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes")
doc
defineAquí hay una respuesta a mi propia pregunta. Combiné las respuestas de los distintos resultados para escribir una clase que imprima bastante XML.
No hay garantías sobre cómo responde con XML inválido o documentos grandes.
fuente
writer.getDomConfig().setParameter("format-pretty-print", Boolean.TRUE);
después de laLSSerializer writer = ...
línea.document
se inicializó la variable , por lo que pensé que podría agregar la desaceleración y hacer un ejemplo rápido de ella. Avíseme si debo cambiar algo, pastebin.com/XL7932aCUna solución más simple basada en esta respuesta :
caso de prueba:
devoluciones:
fuente
factory.setAttribute("indent-number", 4);
y ahora funciona.<?xml version="1.0" encoding="UTF-8"?>
?transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
<?xml version="1.0" encoding="UTF-8"?><root>
está todo en una línea. Alguna idea de por qué?transformer.setOutputProperty(OutputKeys.DOCTYPE_PUBLIC, "yes");
funcionó para mí.Ahora es 2012 y Java puede hacer más de lo que solía hacer con XML, me gustaría agregar una alternativa a mi respuesta aceptada. Esto no tiene dependencias fuera de Java 6.
fuente
Solo para notar que la respuesta mejor calificada requiere el uso de xerces.
Si no desea agregar esta dependencia externa, simplemente puede usar las bibliotecas jdk estándar (que en realidad se crean utilizando xerces internamente).
NB: Hubo un error con la versión 1.5 de jdk, consulte http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6296446 pero ya está resuelto.
(Tenga en cuenta que si se produce un error, esto devolverá el texto original)
fuente
Ya imprimí bastante en el pasado usando el método org.dom4j.io.OutputFormat.createPrettyPrint ()
fuente
prettyPrintedString.replaceAll("\\s+\n", "\n")
Aquí hay una forma de hacerlo usando dom4j :
Importaciones:
Código:
fuente
<?xml version...
en una línea y todo lo demás en otra línea.Dado que está comenzando con a
String
, debe convertirlo en unDOM
objeto (por ejemploNode
) antes de poder usar elTransformer
. Sin embargo, si sabe que su cadena XML es válida y no desea incurrir en la sobrecarga de memoria al analizar una cadena en un DOM, luego ejecute una transformación sobre el DOM para recuperar una cadena; simplemente puede hacer algo antiguo análisis de carácter por carácter. Inserte una nueva línea y espacios después de cada</...>
carácter, mantenga un contador de sangría (para determinar el número de espacios) que incremente para cada uno<...>
y disminuya para cada</...>
que vea.Descargo de responsabilidad: hice una edición de cortar / pegar / texto de las funciones a continuación, por lo que es posible que no se compilen tal como están.
fuente
Si usar una biblioteca XML de terceros está bien, puede salirse con la suya con algo significativamente más simple de lo que sugieren las respuestas más votadas actualmente .
Se indicó que tanto la entrada como la salida deberían ser cadenas, por lo que aquí hay un método de utilidad que hace exactamente eso, implementado con la biblioteca XOM :
Probé que funciona, y los resultados no dependen de su versión de JRE ni nada de eso. Para ver cómo personalizar el formato de salida a su gusto, eche un vistazo a la
Serializer
API.En realidad, esto salió más tiempo de lo que pensaba: se necesitaban algunas líneas adicionales porque
Serializer
quiereOutputStream
escribir. Pero tenga en cuenta que aquí hay muy poco código para el giro XML real.(Esta respuesta es parte de mi evaluación de XOM, que se sugirió como una opción en mi pregunta sobre la mejor biblioteca XML de Java para reemplazar dom4j. Para el registro, con dom4j podría lograr esto con la misma facilidad usando
XMLWriter
yOutputFormat
. Editar : .. Como se demostró en la respuesta de mlo55 .)fuente
Kevin Hakanson dijo: "Sin embargo, si sabe que su cadena XML es válida y no desea incurrir en la sobrecarga de memoria al analizar una cadena en un DOM, luego ejecute una transformación sobre el DOM para recuperar una cadena: podría simplemente realice algunos caracteres anticuados mediante el análisis de caracteres. Inserte una nueva línea y espacios después de cada carácter, mantenga un contador de sangría (para determinar el número de espacios) que incremente por cada <...> y disminuya por cada que vea ".
Convenido. Tal enfoque es mucho más rápido y tiene muchas menos dependencias.
Solución de ejemplo:
fuente
Hmmm ... se enfrentó a algo como esto y es un error conocido ... solo agregue esta OutputProperty ...
Espero que esto ayude ...
fuente
Respecto al comentario de que "primero debe construir un árbol DOM": No, no necesita y no debe hacer eso.
En su lugar, cree un StreamSource (nuevo StreamSource (nuevo StringReader (str)) y alimente eso al transformador de identidad mencionado. Utilizará el analizador SAX y el resultado será mucho más rápido. La construcción de un árbol intermedio es pura sobrecarga para este caso. De lo contrario, la respuesta mejor clasificada es buena.
fuente
Usando scala:
También puede hacer esto en Java, si depende de scala-library.jar. Se parece a esto:
El
PrettyPrinter
objeto se construye con dos entradas, la primera es la longitud máxima de la línea y la segunda el paso de sangría.fuente
versión ligeramente mejorada de milosmns ...
fuente
} else if (row.startsWith("</")) {
parte de esto:else if (row.startsWith("</")) { String indent = repeatIdent(--stack); if (pretty.charAt(pretty.length() - 1) == '\n') { pretty.append(indent + row + "\n"); } else { pretty.append(row + "\n"); } }
Solo para referencia futura, aquí hay una solución que funcionó para mí (gracias a un comentario que @George Hawkins publicó en una de las respuestas):
fuente
Si está seguro de que tiene un XML válido, este es simple y evita árboles XML DOM. Tal vez tiene algunos errores, comente si ve algo
fuente
Todas las soluciones anteriores no funcionaron para mí, entonces encontré este http://myshittycode.com/2014/02/10/java-properly-indenting-xml-string/
La pista es eliminar espacios en blanco con XPath
fuente
Este código a continuación funciona perfectamente
fuente
Los mezclo todos y escribo un pequeño programa. Está leyendo del archivo xml e imprimiendo. Solo en lugar de xzy, proporcione su ruta de archivo.
fuente
Solo otra solución que funciona para nosotros
fuente
Usando jdom2: http://www.jdom.org/
fuente
Como alternativa a las respuestas de max , codeskraps , David Easley y milosmns , eche un vistazo a mi biblioteca de impresoras bonitas livianas y de alto rendimiento: xml-formatter
A veces, como cuando se ejecutan servicios SOAP simulados directamente desde un archivo, es bueno tener una impresora bonita que también maneje XML ya impreso:
Como algunos han comentado, la impresión bonita es solo una forma de presentar XML en una forma más legible para los humanos: los espacios en blanco estrictamente no pertenecen a sus datos XML.
La biblioteca está diseñada para la impresión bonita con fines de registro, y también incluye funciones para el filtrado (eliminación de subárbol / anonimización) y la impresión bonita de XML en CDATA y nodos de texto.
fuente
Tuve el mismo problema y estoy teniendo un gran éxito con JTidy ( http://jtidy.sourceforge.net/index.html )
Ejemplo:
fuente
Underscore-java tiene un método estático
U.formatXml(string)
. Soy el mantenedor del proyecto. Ejemplo en vivoSalida:
fuente
hay una muy buena utilidad de línea de comandos xml llamada xmlstarlet ( http://xmlstar.sourceforge.net/ ) que puede hacer muchas cosas que mucha gente usa.
Podrías ejecutar este programa programáticamente usando Runtime.exec y luego leer el archivo de salida formateado. Tiene más opciones y mejores informes de errores que algunas líneas de código Java pueden proporcionar.
descarga xmlstarlet: http://sourceforge.net/project/showfiles.php?group_id=66612&package_id=64589
fuente
Descubrí que en Java 1.6.0_32 el método normal para imprimir una cadena XML (usando un Transformador con un nulo o identidad xslt) no se comporta como me gustaría si las etiquetas se separan simplemente por espacios en blanco, en lugar de no tener separación texto. Intenté usar
<xsl:strip-space elements="*"/>
mi plantilla en vano. La solución más simple que encontré fue quitar el espacio de la manera que quería usando un filtro SAXSource y XML. Como mi solución fue para el registro, también extendí esto para trabajar con fragmentos XML incompletos. Tenga en cuenta que el método normal parece funcionar bien si usa un DOMSource pero no quería usarlo debido a la incompletitud y la sobrecarga de memoria.fuente
Las soluciones que he encontrado aquí para Java 1.6+ no reformatean el código si ya está formateado. El que funcionó para mí (y volvió a formatear el código ya formateado) fue el siguiente.
Es una buena herramienta para usar en las pruebas unitarias para la comparación xml de cadena completa.
fuente
Para aquellos que buscan una solución rápida y sucia, que no necesita que el XML sea 100% válido. por ejemplo, en caso de registro REST / SOAP (nunca se sabe lo que envían los demás ;-))
Encontré y avancé un código cortado que encontré en línea que creo que todavía falta aquí como un posible enfoque válido:
Aquí está la salida:
fuente
Vi una respuesta usando
Scala
, así que aquí hay otraGroovy
, por si alguien lo encuentra interesante. La sangría predeterminada es de 2 pasos, alXmlNodePrinter
constructor también se le puede pasar otro valor.Uso de Java si groovy jar está en classpath
fuente
En caso de que no necesite tanto sangrado sino algunos saltos de línea, podría ser suficiente simplemente regex ...
El código es bueno, no el resultado debido a la falta de sangría.
(Para soluciones con sangría, vea otras respuestas).
fuente