Comment imprimer assez XML à partir de Java?

J’ai une chaîne Java contenant du code XML, sans saut de ligne ni indentation. Je voudrais en faire une chaîne avec du XML bien formaté. Comment puis-je faire cela?

Ssortingng unformattedXml = "hello"; Ssortingng formattedXml = new [UnknownClass]().format(unformattedXml); 

Remarque: mon entrée est une chaîne . Ma sortie est une chaîne .

 Transformer transformer = TransformerFactory.newInstance().newTransformer(); transformer.setOutputProperty(OutputKeys.INDENT, "yes"); transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2"); //initialize StreamResult with File object to save to file StreamResult result = new StreamResult(new SsortingngWriter()); DOMSource source = new DOMSource(doc); transformer.transform(source, result); Ssortingng xmlSsortingng = result.getWriter().toSsortingng(); System.out.println(xmlSsortingng); 

Remarque: Les résultats peuvent varier en fonction de la version de Java. Recherchez des solutions de contournement spécifiques à votre plate-forme.

Voici une réponse à ma propre question. J’ai combiné les réponses des différents résultats pour écrire une classe qui imprime assez XML.

Aucune garantie sur la façon dont il répond avec XML ou des documents volumineux non valides.

 package ecb.sdw.pretty; import org.apache.xml.serialize.OutputFormat; import org.apache.xml.serialize.XMLSerializer; import org.w3c.dom.Document; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import java.io.IOException; import java.io.SsortingngReader; import java.io.SsortingngWriter; import java.io.Writer; /** * Pretty-prints xml, supplied as a ssortingng. * 

* eg. *
* Ssortingng formattedXml = new XmlFormatter().format("hello"); * */ public class XmlFormatter { public XmlFormatter() { } public Ssortingng format(Ssortingng unformattedXml) { try { final Document document = parseXmlFile(unformattedXml); OutputFormat format = new OutputFormat(document); format.setLineWidth(65); format.setIndenting(true); format.setIndent(2); Writer out = new SsortingngWriter(); XMLSerializer serializer = new XMLSerializer(out, format); serializer.serialize(document); return out.toSsortingng(); } catch (IOException e) { throw new RuntimeException(e); } } private Document parseXmlFile(Ssortingng in) { try { DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); DocumentBuilder db = dbf.newDocumentBuilder(); InputSource is = new InputSource(new SsortingngReader(in)); return db.parse(is); } catch (ParserConfigurationException e) { throw new RuntimeException(e); } catch (SAXException e) { throw new RuntimeException(e); } catch (IOException e) { throw new RuntimeException(e); } } public static void main(Ssortingng[] args) { Ssortingng unformattedXml = "\n" + " \n" + " \n" + " \t\t\t\t\t ECB\n\n\n\n\n" + " \n" + " \n\n\n\n\n" + ""; System.out.println(new XmlFormatter().format(unformattedXml)); } }

une solution plus simple basée sur cette réponse :

 public static Ssortingng prettyFormat(Ssortingng input, int indent) { try { Source xmlInput = new StreamSource(new SsortingngReader(input)); SsortingngWriter ssortingngWriter = new SsortingngWriter(); StreamResult xmlOutput = new StreamResult(ssortingngWriter); TransformerFactory transformerFactory = TransformerFactory.newInstance(); transformerFactory.setAtsortingbute("indent-number", indent); Transformer transformer = transformerFactory.newTransformer(); transformer.setOutputProperty(OutputKeys.INDENT, "yes"); transformer.transform(xmlInput, xmlOutput); return xmlOutput.getWriter().toSsortingng(); } catch (Exception e) { throw new RuntimeException(e); // simple exception handling, please review it } } public static Ssortingng prettyFormat(Ssortingng input) { return prettyFormat(input, 2); } 

cas de test:

 prettyFormat("aaa"); 

résultats:

   aaa   

Maintenant, c’est en 2012 et Java peut faire plus que d’habitude avec XML, j’aimerais append une alternative à ma réponse acceptée. Cela n’a pas de dépendances en dehors de Java 6.

 import org.w3c.dom.Node; import org.w3c.dom.bootstrap.DOMImplementationRegistry; import org.w3c.dom.ls.DOMImplementationLS; import org.w3c.dom.ls.LSSerializer; import org.xml.sax.InputSource; import javax.xml.parsers.DocumentBuilderFactory; import java.io.SsortingngReader; /** * Pretty-prints xml, supplied as a ssortingng. * 

* eg. *
* Ssortingng formattedXml = new XmlFormatter().format("hello"); * */ public class XmlFormatter { public Ssortingng format(Ssortingng xml) { try { final InputSource src = new InputSource(new SsortingngReader(xml)); final Node document = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(src).getDocumentElement(); final Boolean keepDeclaration = Boolean.valueOf(xml.startsWith("\n" + " \n" + " \n" + " \t\t\t\t\t ECB\n\n\n\n\n" + " \n" + " \n\n\n\n\n" + ""; System.out.println(new XmlFormatter().format(unformattedXml)); } }

Juste pour noter que la réponse la mieux notée nécessite l’utilisation de xerces.

Si vous ne voulez pas append cette dépendance externe, vous pouvez simplement utiliser les bibliothèques jdk standard (qui sont en fait construites en utilisant xerces en interne).

NB: Il y avait un bug avec jdk version 1.5 voir http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6296446 mais il est résolu maintenant.,

(Notez que si une erreur survient, cela renverra le texte original)

 package com.test; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import javax.xml.transform.OutputKeys; import javax.xml.transform.Source; import javax.xml.transform.Transformer; import javax.xml.transform.sax.SAXSource; import javax.xml.transform.sax.SAXTransformerFactory; import javax.xml.transform.stream.StreamResult; import org.xml.sax.InputSource; public class XmlTest { public static void main(Ssortingng[] args) { XmlTest t = new XmlTest(); System.out.println(t.formatXml("text D")); } public Ssortingng formatXml(Ssortingng xml){ try{ Transformer serializer= SAXTransformerFactory.newInstance().newTransformer(); serializer.setOutputProperty(OutputKeys.INDENT, "yes"); //serializer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes"); serializer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2"); //serializer.setOutputProperty("{http://xml.customer.org/xslt}indent-amount", "2"); Source xmlSource=new SAXSource(new InputSource(new ByteArrayInputStream(xml.getBytes()))); StreamResult res = new StreamResult(new ByteArrayOutputStream()); serializer.transform(xmlSource, res); return new Ssortingng(((ByteArrayOutputStream)res.getOutputStream()).toByteArray()); }catch(Exception e){ //TODO log error return xml; } } } 

J’ai plutôt imprimé dans le passé en utilisant la méthode org.dom4j.io.OutputFormat.createPrettyPrint ()

 public Ssortingng prettyPrint(final Ssortingng xml){ if (SsortingngUtils.isBlank(xml)) { throw new RuntimeException("xml was null or blank in prettyPrint()"); } final SsortingngWriter sw; try { final OutputFormat format = OutputFormat.createPrettyPrint(); final org.dom4j.Document document = DocumentHelper.parseText(xml); sw = new SsortingngWriter(); final XMLWriter writer = new XMLWriter(sw, format); writer.write(document); } catch (Exception e) { throw new RuntimeException("Error pretty printing xml:\n" + xml, e); } return sw.toSsortingng(); } 

Voici une façon de le faire en utilisant dom4j :

Importations:

 import org.dom4j.Document; import org.dom4j.DocumentHelper; import org.dom4j.io.OutputFormat; import org.dom4j.io.XMLWriter; 

Code:

 Ssortingng xml = ""; Document doc = DocumentHelper.parseText(xml); SsortingngWriter sw = new SsortingngWriter(); OutputFormat format = OutputFormat.createPrettyPrint(); XMLWriter xw = new XMLWriter(sw, format); xw.write(doc); Ssortingng result = sw.toSsortingng(); 

Étant donné que vous commencez par une Ssortingng , vous devez passer à un object DOM (par exemple, un Node ) avant de pouvoir utiliser le Transformer . Cependant, si vous savez que votre chaîne XML est valide et que vous ne voulez pas avoir à gérer la mémoire pour parsingr une chaîne dans un DOM, puis exécuter une transformation sur le DOM pour récupérer une chaîne, vous pouvez vous contenter parsing de caractère par caractère. Insérez une nouvelle ligne et des espaces après chaque caractère, un compteur Keep et Indent (pour déterminer le nombre d’espaces) que vous incrémentez pour chaque <...> et décrément pour chaque vous voyez.

Déni de responsabilité – J’ai effectué une édition couper / coller / texte des fonctions ci-dessous, elles ne peuvent donc pas être compilées telles quelles.

 public static final Element createDOM(Ssortingng strXML) throws ParserConfigurationException, SAXException, IOException { DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); dbf.setValidating(true); DocumentBuilder db = dbf.newDocumentBuilder(); InputSource sourceXML = new InputSource(new SsortingngReader(strXML)) Document xmlDoc = db.parse(sourceXML); Element e = xmlDoc.getDocumentElement(); e.normalize(); return e; } public static final void prettyPrint(Node xml, OutputStream out) throws TransformerConfigurationException, TransformerFactoryConfigurationError, TransformerException { Transformer tf = TransformerFactory.newInstance().newTransformer(); tf.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes"); tf.setOutputProperty(OutputKeys.ENCODING, "UTF-8"); tf.setOutputProperty(OutputKeys.INDENT, "yes"); tf.transform(new DOMSource(xml), new StreamResult(out)); } 

Si l’utilisation d’une bibliothèque XML tierce est correcte, vous pouvez vous en sortir avec quelque chose de beaucoup plus simple que ce que suggèrent les réponses actuellement les plus votées .

Il a été déclaré que les entrées et les sorties doivent être des chaînes de caractères, alors voici une méthode d’utilitaire qui fait exactement cela, implémentée avec la bibliothèque XOM :

 import nu.xom.*; import java.io.*; [...] public static Ssortingng format(Ssortingng xml) throws ParsingException, IOException { ByteArrayOutputStream out = new ByteArrayOutputStream(); Serializer serializer = new Serializer(out); serializer.setIndent(4); // or whatever you like serializer.write(new Builder().build(xml, "")); return out.toSsortingng("UTF-8"); } 

J’ai testé que cela fonctionne, et les résultats ne dépendent pas de votre version de JRE ou de quelque chose comme ça. Pour voir comment personnaliser le format de sortie à votre goût, consultez l’API Serializer .

Cela a en fait OutputStream plus longtemps que je ne le pensais – certaines lignes supplémentaires étaient nécessaires car Serializer veut qu’un OutputStream écrive. Mais notez qu’il y a très peu de code pour le twiddling XML réel ici.

(Cette réponse fait partie de mon évaluation de XOM, qui a été suggérée comme une option dans ma question sur la meilleure bibliothèque Java XML pour remplacer dom4j. Pour mémoire, avec dom4j, vous pouviez réaliser cela facilement avec XMLWriter et OutputFormat . … comme démontré dans la réponse de mlo55 .)

Kevin Hakanson a déclaré: “Cependant, si vous savez que votre chaîne XML est valide et que vous ne voulez pas avoir à gérer la mémoire pour parsingr une chaîne dans un DOM, puis exécuter une transformation sur le DOM pour récupérer une chaîne, vous pouvez Il suffit de faire une parsing syntaxique caractère par caractère. Insérez une nouvelle ligne et des espaces après chaque caractère, un compteur Keep et Indent (pour déterminer le nombre d’espaces) que vous incrémentez pour chaque <...> et chaque décrément. ”

D’accord. Une telle approche est beaucoup plus rapide et comporte beaucoup moins de dépendances.

Exemple de solution:

 /** * XML utils, including formatting. */ public class XmlUtils { private static XmlFormatter formatter = new XmlFormatter(2, 80); public static Ssortingng formatXml(Ssortingng s) { return formatter.format(s, 0); } public static Ssortingng formatXml(Ssortingng s, int initialIndent) { return formatter.format(s, initialIndent); } private static class XmlFormatter { private int indentNumChars; private int lineLength; private boolean singleLine; public XmlFormatter(int indentNumChars, int lineLength) { this.indentNumChars = indentNumChars; this.lineLength = lineLength; } public synchronized Ssortingng format(Ssortingng s, int initialIndent) { int indent = initialIndent; SsortingngBuilder sb = new SsortingngBuilder(); for (int i = 0; i < s.length(); i++) { char currentChar = s.charAt(i); if (currentChar == '<') { char nextChar = s.charAt(i + 1); if (nextChar == '/') indent -= indentNumChars; if (!singleLine) // Don't indent before closing element if we're creating opening and closing elements on a single line. sb.append(buildWhitespace(indent)); if (nextChar != '?' && nextChar != '!' && nextChar != '/') indent += indentNumChars; singleLine = false; // Reset flag. } sb.append(currentChar); if (currentChar == '>') { if (s.charAt(i - 1) == '/') { indent -= indentNumChars; sb.append("\n"); } else { int nextStartElementPos = s.indexOf('<', i); if (nextStartElementPos > i + 1) { Ssortingng textBetweenElements = s.subssortingng(i + 1, nextStartElementPos); // If the space between elements is solely newlines, let them through to preserve additional newlines in source document. if (textBetweenElements.replaceAll("\n", "").length() == 0) { sb.append(textBetweenElements + "\n"); } // Put tags and text on a single line if the text is short. else if (textBetweenElements.length() <= lineLength * 0.5) { sb.append(textBetweenElements); singleLine = true; } // For larger amounts of text, wrap lines to a maximum line length. else { sb.append("\n" + lineWrap(textBetweenElements, lineLength, indent, null) + "\n"); } i = nextStartElementPos - 1; } else { sb.append("\n"); } } } } return sb.toString(); } } private static String buildWhitespace(int numChars) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < numChars; i++) sb.append(" "); return sb.toString(); } /** * Wraps the supplied text to the specified line length. * @lineLength the maximum length of each line in the returned string (not including indent if specified). * @indent optional number of whitespace characters to prepend to each line before the text. * @linePrefix optional string to append to the indent (before the text). * @returns the supplied text wrapped so that no line exceeds the specified line length + indent, optionally with * indent and prefix applied to each line. */ private static String lineWrap(String s, int lineLength, Integer indent, String linePrefix) { if (s == null) return null; StringBuilder sb = new StringBuilder(); int lineStartPos = 0; int lineEndPos; boolean firstLine = true; while(lineStartPos < s.length()) { if (!firstLine) sb.append("\n"); else firstLine = false; if (lineStartPos + lineLength > s.length()) lineEndPos = s.length() - 1; else { lineEndPos = lineStartPos + lineLength - 1; while (lineEndPos > lineStartPos && (s.charAt(lineEndPos) != ' ' && s.charAt(lineEndPos) != '\t')) lineEndPos--; } sb.append(buildWhitespace(indent)); if (linePrefix != null) sb.append(linePrefix); sb.append(s.subssortingng(lineStartPos, lineEndPos + 1)); lineStartPos = lineEndPos + 1; } return sb.toSsortingng(); } // other utils removed for brevity } 

Hmmm … fait face à quelque chose comme ça et c’est un bug connu … il suffit d’append cette OutputProperty ..

 transformer.setOutputProperty(OutputPropertiesFactory.S_KEY_INDENT_AMOUNT, "8"); 

J’espère que cela t’aides …

En utilisant Scala:

 import xml._ val xml = XML.loadSsortingng("hello") val formatted = new PrettyPrinter(150, 2).format(xml) println(formatted) 

Vous pouvez aussi le faire en Java si vous dépendez de scala-library.jar. Cela ressemble à ceci:

 import scala.xml.*; public class FormatXML { public static void main(Ssortingng[] args) { Ssortingng unformattedXml = "hello"; PrettyPrinter pp = new PrettyPrinter(150, 3); Ssortingng formatted = pp.format(XML.loadSsortingng(unformattedXml), TopScope$.MODULE$); System.out.println(formatted); } } 

L’object PrettyPrinter est construit avec deux ints, le premier étant la longueur maximale de la ligne et le second étant l’étape d’indentation.

En ce qui concerne le commentaire “vous devez d’abord construire un arbre DOM”: non, vous n’avez pas besoin et vous ne devriez pas le faire.

Au lieu de cela, créez un StreamSource (new StreamSource (new SsortingngReader (str)) et transmettez-le au transformateur d’identité mentionné. Cela utilisera l’parsingur SAX, et le résultat sera beaucoup plus rapide. La construction d’un arbre intermédiaire est pure pour ce cas. Sinon, la réponse la mieux classée est bonne.

Juste pour référence future, voici une solution qui a fonctionné pour moi (grâce à un commentaire que @ George Hawkins a publié dans l’une des réponses):

 DOMImplementationRegistry registry = DOMImplementationRegistry.newInstance(); DOMImplementationLS impl = (DOMImplementationLS) registry.getDOMImplementation("LS"); LSSerializer writer = impl.createLSSerializer(); writer.getDomConfig().setParameter("format-pretty-print", Boolean.TRUE); LSOutput output = impl.createLSOutput(); ByteArrayOutputStream out = new ByteArrayOutputStream(); output.setByteStream(out); writer.write(document, output); Ssortingng xmlStr = new Ssortingng(out.toByteArray()); 

version légèrement améliorée de milosmns …

 public static Ssortingng getPrettyXml(Ssortingng xml) { if (xml == null || xml.sortingm().length() == 0) return ""; int stack = 0; SsortingngBuilder pretty = new SsortingngBuilder(); Ssortingng[] rows = xml.sortingm().replaceAll(">", ">\n").replaceAll("<", "\n<").split("\n"); for (int i = 0; i < rows.length; i++) { if (rows[i] == null || rows[i].trim().length() == 0) continue; String row = rows[i].trim(); if (row.startsWith("") == false) { Ssortingng indent = repeatSsortingng(stack++); pretty.append(indent + row + "\n"); if (row.endsWith("]]>")) stack--; } else { Ssortingng indent = repeatSsortingng(stack); pretty.append(indent + row + "\n"); } } return pretty.toSsortingng().sortingm(); } private static Ssortingng repeatSsortingng(int stack) { SsortingngBuilder indent = new SsortingngBuilder(); for (int i = 0; i < stack; i++) { indent.append(" "); } return indent.toString(); } 

Si vous êtes certain d’avoir un XML valide, celui-ci est simple et évite les arborescences DOM XML. Peut-être a-t-il des bugs, commentez si vous voyez quelque chose

 public Ssortingng prettyPrint(Ssortingng xml) { if (xml == null || xml.sortingm().length() == 0) return ""; int stack = 0; SsortingngBuilder pretty = new SsortingngBuilder(); Ssortingng[] rows = xml.sortingm().replaceAll(">", ">\n").replaceAll("<", "\n<").split("\n"); for (int i = 0; i < rows.length; i++) { if (rows[i] == null || rows[i].trim().length() == 0) continue; String row = rows[i].trim(); if (row.startsWith(" 

Toutes les solutions ci-dessus n’ont pas fonctionné pour moi, alors j’ai trouvé ceci http://myshittycode.com/2014/02/10/java-properly-indenting-xml-ssortingng/

La clé est de supprimer les espaces blancs avec XPath

  Ssortingng xml = "" + "\n " + "\nCoco Puff" + "\n 10 "; try { Document document = DocumentBuilderFactory.newInstance() .newDocumentBuilder() .parse(new InputSource(new ByteArrayInputStream(xml.getBytes("utf-8")))); XPath xPath = XPathFactory.newInstance().newXPath(); NodeList nodeList = (NodeList) xPath.evaluate("//text()[normalize-space()='']", document, XPathConstants.NODESET); for (int i = 0; i < nodeList.getLength(); ++i) { Node node = nodeList.item(i); node.getParentNode().removeChild(node); } Transformer transformer = TransformerFactory.newInstance().newTransformer(); transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8"); transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes"); transformer.setOutputProperty(OutputKeys.INDENT, "yes"); transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4"); StringWriter stringWriter = new StringWriter(); StreamResult streamResult = new StreamResult(stringWriter); transformer.transform(new DOMSource(document), streamResult); System.out.println(stringWriter.toString()); } catch (Exception e) { e.printStackTrace(); } 

Juste une autre solution qui fonctionne pour nous

 import java.io.SsortingngWriter; import org.dom4j.DocumentHelper; import org.dom4j.io.OutputFormat; import org.dom4j.io.XMLWriter; ** * Pretty Print XML Ssortingng * * @param inputXmlSsortingng * @return */ public static Ssortingng prettyPrintXml(Ssortingng xml) { final SsortingngWriter sw; try { final OutputFormat format = OutputFormat.createPrettyPrint(); final org.dom4j.Document document = DocumentHelper.parseText(xml); sw = new SsortingngWriter(); final XMLWriter writer = new XMLWriter(sw, format); writer.write(document); } catch (Exception e) { throw new RuntimeException("Error pretty printing xml:\n" + xml, e); } return sw.toSsortingng(); } 

Ce code ci-dessous fonctionne parfaitement

 import javax.xml.transform.OutputKeys; import javax.xml.transform.Source; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerFactory; import javax.xml.transform.stream.StreamResult; import javax.xml.transform.stream.StreamSource; Ssortingng formattedXml1 = prettyFormat("aaa"); public static Ssortingng prettyFormat(Ssortingng input) { return prettyFormat(input, "2"); } public static Ssortingng prettyFormat(Ssortingng input, Ssortingng indent) { Source xmlInput = new StreamSource(new SsortingngReader(input)); SsortingngWriter ssortingngWriter = new SsortingngWriter(); try { TransformerFactory transformerFactory = TransformerFactory.newInstance(); Transformer transformer = transformerFactory.newTransformer(); transformer.setOutputProperty(OutputKeys.INDENT, "yes"); transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", indent); transformer.transform(xmlInput, new StreamResult(ssortingngWriter)); Ssortingng pretty = ssortingngWriter.toSsortingng(); pretty = pretty.replace("\r\n", "\n"); return pretty; } catch (Exception e) { throw new RuntimeException(e); } } 

As an alternative to the answers from max , codeskraps , David Easley and milosmns , have a look at my lightweight, high-performance pretty-printer library: xml-formatter

 // construct lightweight, threadsafe, instance PrettyPrinter prettyPrinter = PrettyPrinterBuilder.newPrettyPrinter().build(); SsortingngBuilder buffer = new SsortingngBuilder(); Ssortingng xml = ..; // also works with char[] or Reader if(prettyPrinter.process(xml, buffer)) { // valid XML, print buffer } else { // invalid XML, print xml } 

Sometimes, like when running mocked SOAP services directly from file, it is good to have a pretty-printer which also handles already pretty-printed XML:

 PrettyPrinter prettyPrinter = PrettyPrinterBuilder.newPrettyPrinter().ignoreWhitespace().build(); 

As some have commented, pretty-printing is just a way of presenting XML in a more human-readable form – whitespace ssortingctly does not belong in your XML data.

The library is intended for pretty-printing for logging purposes, and also includes functions for filtering (subtree removal / anonymization) and pretty-printing of XML in CDATA and Text nodes.

I had the same problem and I’m having great success with JTidy ( http://jtidy.sourceforge.net/index.html )

Exemple:

 Tidy t = new Tidy(); t.setIndentContent(true); Document d = t.parseDOM( new ByteArrayInputStream("HTML goes here", null); OutputStream out = new ByteArrayOutputStream(); t.pprint(d, out); Ssortingng html = out.toSsortingng(); 

Using jdom2 : http://www.jdom.org/

 import java.io.SsortingngReader; import org.jdom2.input.SAXBuilder; import org.jdom2.output.Format; import org.jdom2.output.XMLOutputter; Ssortingng prettyXml = new XMLOutputter(Format.getPrettyFormat()). outputSsortingng(new SAXBuilder().build(new SsortingngReader(uglyXml))); 

there is a very nice command line xml utility called xmlstarlet( http://xmlstar.sourceforge.net/ ) that can do a lot of things which a lot of people use.

Your could execute this program programatically using Runtime.exec and then readin the formatted output file. It has more options and better error reporting than a few lines of Java code can provide.

download xmlstarlet : http://sourceforge.net/project/showfiles.php?group_id=66612&package_id=64589

I have found that in Java 1.6.0_32 the normal method to pretty print an XML ssortingng (using a Transformer with a null or identity xslt) does not behave as I would like if tags are merely separated by whitespace, as opposed to having no separating text. I sortinged using in my template to no avail. The simplest solution I found was to ssortingp the space the way I wanted using a SAXSource and XML filter. Since my solution was for logging I also extended this to work with incomplete XML fragments. Note the normal method seems to work fine if you use a DOMSource but I did not want to use this because of the incompleteness and memory overhead.

 public static class WhitespaceIgnoreFilter extends XMLFilterImpl { @Override public void ignorableWhitespace(char[] arg0, int arg1, int arg2) throws SAXException { //Ignore it then... } @Override public void characters( char[] ch, int start, int length) throws SAXException { if (!new Ssortingng(ch, start, length).sortingm().equals("")) super.characters(ch, start, length); } } public static Ssortingng prettyXML(Ssortingng logMsg, boolean allowBadlyFormedFragments) throws SAXException, IOException, TransformerException { TransformerFactory transFactory = TransformerFactory.newInstance(); transFactory.setAtsortingbute("indent-number", new Integer(2)); Transformer transformer = transFactory.newTransformer(); transformer.setOutputProperty(OutputKeys.INDENT, "yes"); transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4"); SsortingngWriter out = new SsortingngWriter(); XMLReader masterParser = SAXHelper.getSAXParser(true); XMLFilter parser = new WhitespaceIgnoreFilter(); parser.setParent(masterParser); if(allowBadlyFormedFragments) { transformer.setErrorListener(new ErrorListener() { @Override public void warning(TransformerException exception) throws TransformerException { } @Override public void fatalError(TransformerException exception) throws TransformerException { } @Override public void error(TransformerException exception) throws TransformerException { } }); } try { transformer.transform(new SAXSource(parser, new InputSource(new SsortingngReader(logMsg))), new StreamResult(out)); } catch (TransformerException e) { if(e.getCause() != null && e.getCause() instanceof SAXParseException) { if(!allowBadlyFormedFragments || !"XML document structures must start and end within the same entity.".equals(e.getCause().getMessage())) { throw e; } } else { throw e; } } out.flush(); return out.toSsortingng(); } 

The solutions I have found here for Java 1.6+ do not reformat the code if it is already formatted. The one that worked for me (and re-formatted already formatted code) was the following.

 import org.apache.xml.security.c14n.CanonicalizationException; import org.apache.xml.security.c14n.Canonicalizer; import org.apache.xml.security.c14n.InvalidCanonicalizerException; import org.w3c.dom.Element; import org.w3c.dom.bootstrap.DOMImplementationRegistry; import org.w3c.dom.ls.DOMImplementationLS; import org.w3c.dom.ls.LSSerializer; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.TransformerException; import java.io.IOException; import java.io.SsortingngReader; public class XmlUtils { public static Ssortingng toCanonicalXml(Ssortingng xml) throws InvalidCanonicalizerException, ParserConfigurationException, SAXException, CanonicalizationException, IOException { Canonicalizer canon = Canonicalizer.getInstance(Canonicalizer.ALGO_ID_C14N_OMIT_COMMENTS); byte canonXmlBytes[] = canon.canonicalize(xml.getBytes()); return new Ssortingng(canonXmlBytes); } public static Ssortingng prettyFormat(Ssortingng input) throws TransformerException, ParserConfigurationException, IOException, SAXException, InstantiationException, IllegalAccessException, ClassNotFoundException { InputSource src = new InputSource(new SsortingngReader(input)); Element document = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(src).getDocumentElement(); Boolean keepDeclaration = input.startsWith(" 

It is a good tool to use in your unit tests for full-ssortingng xml comparison.

 private void assertXMLEqual(Ssortingng expected, Ssortingng actual) throws ParserConfigurationException, IOException, SAXException, CanonicalizationException, InvalidCanonicalizerException, TransformerException, IllegalAccessException, ClassNotFoundException, InstantiationException { Ssortingng canonicalExpected = prettyFormat(toCanonicalXml(expected)); Ssortingng canonicalActual = prettyFormat(toCanonicalXml(actual)); assertEquals(canonicalExpected, canonicalActual); } 

For those searching for a quick and dirty solution – which doesn’t need the XML to be 100% valid. eg in case of REST / SOAP logging (you never know what the others send ;-))

I found and advanced a code snipped I found online which I think is still missing here as a valid possible approach:

 public static Ssortingng prettyPrintXMLAsSsortingng(Ssortingng xmlSsortingng) { /* Remove new lines */ final Ssortingng LINE_BREAK = "\n"; xmlSsortingng = xmlSsortingng.replaceAll(LINE_BREAK, ""); SsortingngBuffer prettyPrintXml = new SsortingngBuffer(); /* Group the xml tags */ Pattern pattern = Pattern.comstack("(<[^/][^>]+>)?([^<]*)(]+>)?(<[^/][^>]+/>)?"); Matcher matcher = pattern.matcher(xmlSsortingng); int tabCount = 0; while (matcher.find()) { Ssortingng str1 = (null == matcher.group(1) || "null".equals(matcher.group())) ? "" : matcher.group(1); Ssortingng str2 = (null == matcher.group(2) || "null".equals(matcher.group())) ? "" : matcher.group(2); Ssortingng str3 = (null == matcher.group(3) || "null".equals(matcher.group())) ? "" : matcher.group(3); Ssortingng str4 = (null == matcher.group(4) || "null".equals(matcher.group())) ? "" : matcher.group(4); if (matcher.group() != null && !matcher.group().sortingm().equals("")) { printTabs(tabCount, prettyPrintXml); if (!str1.equals("") && str3.equals("")) { ++tabCount; } if (str1.equals("") && !str3.equals("")) { --tabCount; prettyPrintXml.deleteCharAt(prettyPrintXml.length() - 1); } prettyPrintXml.append(str1); prettyPrintXml.append(str2); prettyPrintXml.append(str3); if (!str4.equals("")) { prettyPrintXml.append(LINE_BREAK); printTabs(tabCount, prettyPrintXml); prettyPrintXml.append(str4); } prettyPrintXml.append(LINE_BREAK); } } return prettyPrintXml.toSsortingng(); } private static void printTabs(int count, SsortingngBuffer ssortingngBuffer) { for (int i = 0; i < count; i++) { stringBuffer.append("\t"); } } public static void main(String[] args) { String x = new String( "soap:ClientINVALID_MESSAGE20007INVALID_MESSAGEProblems creating SAAJ object model"); System.out.println(prettyPrintXMLAsSsortingng(x)); } 

here is the output:

    soap:Client INVALID_MESSAGE   20007 INVALID_MESSAGE Problems creating SAAJ object model      

I saw one answer using Scala , so here is another one in Groovy , just in case someone finds it interesting. The default indentation is 2 steps, XmlNodePrinter constructor can be passed another value as well.

 def xml = "hello" def ssortingngWriter = new SsortingngWriter() def node = new XmlParser().parseText(xml); new XmlNodePrinter(new PrintWriter(ssortingngWriter)).print(node) println ssortingngWriter.toSsortingng() 

Usage from Java if groovy jar is in classpath

  Ssortingng xml = "hello"; SsortingngWriter ssortingngWriter = new SsortingngWriter(); Node node = new XmlParser().parseText(xml); new XmlNodePrinter(new PrintWriter(ssortingngWriter)).print(node); System.out.println(ssortingngWriter.toSsortingng()); 

In case you do not need indentation that much but a few line breaks, it could be sufficient to simply regex…

 Ssortingng leastPrettifiedXml = uglyXml.replaceAll("><", ">\n<"); 

The code is nice, not the result because of missing indentation.


(For solutions with indentation, see other answers.)

Essaye ça:

  try { TransformerFactory transFactory = TransformerFactory.newInstance(); Transformer transformer = null; transformer = transFactory.newTransformer(); SsortingngWriter buffer = new SsortingngWriter(); transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes"); transformer.transform(new DOMSource(element), new StreamResult(buffer)); Ssortingng str = buffer.toSsortingng(); System.out.println("XML INSIDE IS #########################################"+str); return element; } catch (TransformerConfigurationException e) { e.printStackTrace(); } catch (TransformerException e) { e.printStackTrace(); } 

I should have looked for this page first before coming up with my own solution! Anyway, mine uses Java recursion to parse the xml page. This code is totally self-contained and does not rely on third party libraries. Also .. it uses recursion!

 // you call this method passing in the xml text public static void prettyPrint(Ssortingng text){ prettyPrint(text, 0); } // "index" corresponds to the number of levels of nesting and/or the number of tabs to print before printing the tag public static void prettyPrint(Ssortingng xmlText, int index){ boolean foundTagStart = false; SsortingngBuilder tagChars = new SsortingngBuilder(); Ssortingng startTag = ""; Ssortingng endTag = ""; Ssortingng[] chars = xmlText.split(""); // find the next start tag for(Ssortingng ch : chars){ if(ch.equalsIgnoreCase("<")){ tagChars.append(ch); foundTagStart = true; } else if(ch.equalsIgnoreCase(">") && foundTagStart){ startTag = tagChars.append(ch).toSsortingng(); Ssortingng tempTag = startTag; endTag = (tempTag.contains("\"") ? (tempTag.split(" ")[0] + ">") : tempTag).replace("<", " =>  break; } else if(foundTagStart){ tagChars.append(ch); } } // once start and end tag are calculated, print start tag, then content, then end tag if(foundTagStart){ int startIndex = xmlText.indexOf(startTag); int endIndex = xmlText.indexOf(endTag); // handle if matching tags NOT found if((startIndex < 0) || (endIndex < 0)){ if(startIndex < 0) { // no start tag found return; } else { // start tag found, no end tag found (handles single tags aka "" or "") printTabs(index); System.out.println(startTag); // move on to the next tag // NOTE: "index" (not index+1) because next tag is on same level as this one prettyPrint(xmlText.subssortingng(startIndex+startTag.length(), xmlText.length()), index); return; } // handle when matching tags found } else { Ssortingng content = xmlText.subssortingng(startIndex+startTag.length(), endIndex); boolean isTagContainsTags = content.contains("<"); // content contains tags printTabs(index); if(isTagContainsTags){ // ie: stuff System.out.println(startTag); prettyPrint(content, index+1); // "index+1" because "content" is nested printTabs(index); } else { System.out.print(startTag); // ie: stuff or  System.out.print(content); } System.out.println(endTag); int nextIndex = endIndex + endTag.length(); if(xmlText.length() > nextIndex){ // if there are more tags on this level, continue prettyPrint(xmlText.subssortingng(nextIndex, xmlText.length()), index); } } } else { System.out.print(xmlText); } } private static void printTabs(int counter){ while(counter-- > 0){ System.out.print("\t"); } }