Java'dan XML nasıl güzel yazdırılır?


443

Hiçbir satır beslemeleri veya girintileri ile XML içeren bir Java dize var. Güzel biçimlendirilmiş XML ile bir dize dönüştürmek istiyorum. Bunu nasıl yaparım?

String unformattedXml = "<tag><nested>hello</nested></tag>";
String formattedXml = new [UnknownClass]().format(unformattedXml);

Not: Girişim bir String . Benim çıktı bir String .

(Temel) sahte sonuç:

<?xml version="1.0" encoding="UTF-8"?>
<root>
  <tag>
    <nested>hello</nested>
  </tag>
</root>


10
Sadece merak ediyorum, bu çıktıyı bir XML dosyasına mı yoksa girintinin gerçekten önemli olduğu başka bir şeye mi gönderiyorsunuz? Bir süre önce düzgün bir şekilde görüntülenmesi için XML'imi biçimlendirmekten çok endişeliydim ... ancak bunun için bir süre geçirdikten sonra çıktımı bir web tarayıcısına ve nispeten modern bir web tarayıcısına göndermek zorunda olduğumu fark ettim. XML'i güzel bir ağaç yapısında gösterecek, bu yüzden bu sorunu unutabilir ve devam edebilirim. Siz (veya aynı problemi olan başka bir kullanıcının) aynı ayrıntıyı gözden kaçırmış olması ihtimalinden bahsediyorum.
Abel Morelos

3
@Abel, metin dosyalarına kaydetme, HTML metin alanına ekleme ve hata ayıklama amacıyla konsola aktarma.
Steve McLeod

2
"çok geniş tutun" - şu anda sorunun daha kesin olmak zor!
Steve McLeod

Yanıtlar:


266
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 StringWriter());
DOMSource source = new DOMSource(doc);
transformer.transform(source, result);
String xmlString = result.getWriter().toString();
System.out.println(xmlString);

Not: Sonuçlar Java sürümüne bağlı olarak değişebilir. Platformunuza özgü geçici çözümleri arayın.


1
Çıktı içermeyecek şekilde nasıl yapılır <?xml version="1.0" encoding="UTF-8"?>?
Thang Pham

19
Omit için <?xml ...>beyanname, eklentitransformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes")
rustyx

4
Sıradan okuyucular, burada açıklanan çözümün geliştirilmiş bir sürümünü bulabilir ( stackoverflow.com/a/33541820/363573 ).
Stephan

5
nerede doctanımlanır?
Florian F

6
Bu sorumu yanıtlamıyor: XML içeren bir String'i nasıl formatlayabilirim? Bu yanıt, String nesnesini bir şekilde başka bir nesneye dönüştürdüğünüzü zaten varsayar.
Steve McLeod

135

İşte kendi soruma bir cevap. Çeşitli sonuçlardan gelen cevapları bir araya getirerek XML yazdıran bir sınıf yazdım.

Geçersiz XML veya büyük belgelerle nasıl yanıt verdiğine dair bir garanti yoktur.

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.StringReader;
import java.io.StringWriter;
import java.io.Writer;

/**
 * Pretty-prints xml, supplied as a string.
 * <p/>
 * eg.
 * <code>
 * String formattedXml = new XmlFormatter().format("<tag><nested>hello</nested></tag>");
 * </code>
 */
public class XmlFormatter {

    public XmlFormatter() {
    }

    public String format(String unformattedXml) {
        try {
            final Document document = parseXmlFile(unformattedXml);

            OutputFormat format = new OutputFormat(document);
            format.setLineWidth(65);
            format.setIndenting(true);
            format.setIndent(2);
            Writer out = new StringWriter();
            XMLSerializer serializer = new XMLSerializer(out, format);
            serializer.serialize(document);

            return out.toString();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    private Document parseXmlFile(String in) {
        try {
            DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
            DocumentBuilder db = dbf.newDocumentBuilder();
            InputSource is = new InputSource(new StringReader(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(String[] args) {
        String unformattedXml =
                "<?xml version=\"1.0\" encoding=\"UTF-8\"?><QueryMessage\n" +
                        "        xmlns=\"http://www.SDMX.org/resources/SDMXML/schemas/v2_0/message\"\n" +
                        "        xmlns:query=\"http://www.SDMX.org/resources/SDMXML/schemas/v2_0/query\">\n" +
                        "    <Query>\n" +
                        "        <query:CategorySchemeWhere>\n" +
                        "   \t\t\t\t\t         <query:AgencyID>ECB\n\n\n\n</query:AgencyID>\n" +
                        "        </query:CategorySchemeWhere>\n" +
                        "    </Query>\n\n\n\n\n" +
                        "</QueryMessage>";

        System.out.println(new XmlFormatter().format(unformattedXml));
    }

}

13
Sadece bu cevabın Xerces kullanımını gerektirdiğini belirtmek için. Bu bağımlılığı eklemek istemiyorsanız, standart jdk kitaplıklarını ve javax.xml.transform.Transformer'ı kullanabilirsiniz (aşağıdaki
cevabıma

45
2008'de bu iyi bir cevaptı, ama şimdi tüm bunlar Apache sınıfları yerine standart JDK sınıflarıyla yapılabilir. Bkz. Xerces.apache.org/xerces2-j/faq-general.html#faq-6 . Evet, bu bir Xerces SSS'dir ancak cevap standart JDK sınıflarını kapsar. Bu sınıfların ilk 1.5 uygulamasının birçok sorunu vardı, ancak her şey 1.6'dan beri iyi çalışıyor. SSS'deki LSSerializer örneğini kopyalayın, "..." bitini writer.getDomConfig().setParameter("format-pretty-print", Boolean.TRUE);kesin ve LSSerializer writer = ...satırdan sonra ekleyin .
George Hawkins

2
@GeorgeHawkins'in link verdiği Apache'nin verdiği örneği kullanarak küçük bir sınıf oluşturdum. Değişkenin nasıl documentbaşlatıldığını eksikti , bu yüzden yavaşlamaya ekleyebileceğimi ve hızlı bir örnek verebileceğimi düşündüm. Bir şeyi değiştirmem gerekirse bana bildirin, pastebin.com/XL7932aC
samwell

bunu sadece jdk ile yapabileceğiniz doğru değil. en azından güvenilir değil. varsayılan olarak benim jdk7u72 ile etkin olmayan bazı iç kayıt defteri uygulamasına bağlıdır. böylece doğrudan apache malzemelerini daha iyi kullanabilirsiniz.
user1050755

İşte bağımlılığı olmayan bir çözüm: stackoverflow.com/a/33541820/363573 .
Stephan

131

bu cevaba dayanan daha basit bir çözüm :

public static String prettyFormat(String input, int indent) {
    try {
        Source xmlInput = new StreamSource(new StringReader(input));
        StringWriter stringWriter = new StringWriter();
        StreamResult xmlOutput = new StreamResult(stringWriter);
        TransformerFactory transformerFactory = TransformerFactory.newInstance();
        transformerFactory.setAttribute("indent-number", indent);
        Transformer transformer = transformerFactory.newTransformer(); 
        transformer.setOutputProperty(OutputKeys.INDENT, "yes");
        transformer.transform(xmlInput, xmlOutput);
        return xmlOutput.getWriter().toString();
    } catch (Exception e) {
        throw new RuntimeException(e); // simple exception handling, please review it
    }
}

public static String prettyFormat(String input) {
    return prettyFormat(input, 2);
}

test durumu:

prettyFormat("<root><child>aaa</child><child/></root>");

İadeler:

<?xml version="1.0" encoding="UTF-8"?>
<root>
  <child>aaa</child>
  <child/>
</root>

1
Bu her zaman kullandığım kod ama bu şirket işe yaramadı, başka bir XML dönüştürme kitaplığı kullandıklarını varsayıyorum. Fabrikayı ayrı bir hat olarak yarattım ve yaptım factory.setAttribute("indent-number", 4);ve şimdi çalışıyor.
Adrian Smith

Çıktı içermeyecek şekilde nasıl yapılır <?xml version="1.0" encoding="UTF-8"?>?
Thang Pham

4
@Harry:transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
jjmontes

5
Merhaba ben bu tam kodu kullanıyorum, ve ilk eleman hariç düzgün benimkileri biçer Yani, bu: <?xml version="1.0" encoding="UTF-8"?><root>hepsi bir satırda. Neden herhangi bir fikir?
CodyK

2
@Codemiester: Bir hata gibi görünüyor (bkz. Stackoverflow.com/a/18251901/3375325 ). Eklemek transformer.setOutputProperty(OutputKeys.DOCTYPE_PUBLIC, "yes");benim için çalıştı.
jansohn

100

Şimdi 2012 ve Java XML ile eskisinden daha fazlasını yapabilir, kabul edilen cevabım için bir alternatif eklemek istiyorum. Bunun Java 6 dışında bir bağımlılığı yoktur.

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.StringReader;

/**
 * Pretty-prints xml, supplied as a string.
 * <p/>
 * eg.
 * <code>
 * String formattedXml = new XmlFormatter().format("<tag><nested>hello</nested></tag>");
 * </code>
 */
public class XmlFormatter {

    public String format(String xml) {

        try {
            final InputSource src = new InputSource(new StringReader(xml));
            final Node document = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(src).getDocumentElement();
            final Boolean keepDeclaration = Boolean.valueOf(xml.startsWith("<?xml"));

        //May need this: System.setProperty(DOMImplementationRegistry.PROPERTY,"com.sun.org.apache.xerces.internal.dom.DOMImplementationSourceImpl");


            final DOMImplementationRegistry registry = DOMImplementationRegistry.newInstance();
            final DOMImplementationLS impl = (DOMImplementationLS) registry.getDOMImplementation("LS");
            final LSSerializer writer = impl.createLSSerializer();

            writer.getDomConfig().setParameter("format-pretty-print", Boolean.TRUE); // Set this to true if the output needs to be beautified.
            writer.getDomConfig().setParameter("xml-declaration", keepDeclaration); // Set this to true if the declaration is needed to be outputted.

            return writer.writeToString(document);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public static void main(String[] args) {
        String unformattedXml =
                "<?xml version=\"1.0\" encoding=\"UTF-8\"?><QueryMessage\n" +
                        "        xmlns=\"http://www.SDMX.org/resources/SDMXML/schemas/v2_0/message\"\n" +
                        "        xmlns:query=\"http://www.SDMX.org/resources/SDMXML/schemas/v2_0/query\">\n" +
                        "    <Query>\n" +
                        "        <query:CategorySchemeWhere>\n" +
                        "   \t\t\t\t\t         <query:AgencyID>ECB\n\n\n\n</query:AgencyID>\n" +
                        "        </query:CategorySchemeWhere>\n" +
                        "    </Query>\n\n\n\n\n" +
                        "</QueryMessage>";

        System.out.println(new XmlFormatter().format(unformattedXml));
    }
}

Girinti yok, ancak şu şekilde çalışır: System.setProperty (DOMImplementationRegistry.PROPERTY, "com.sun.org.apache.xerces.internal.dom.DOMImplementationSourceImpl");
ggb667

1
Bu örneğe nasıl girinti eklersiniz?
ggb667

2
@DanTemple Kodlamayı kontrol etmek için LSOutput kullanmanız gerekiyor gibi görünüyor. Bkz. Chipkillmar.net/2009/03/25/pretty-print-xml-from-a-dom
Joshua Davis

1
Bunu Andriod'da kullanmaya çalıştım ama `DOMImplementationRegistry 'paketini bulamıyorum. Java 8 kullanıyorum.
Chintan Soni

2
ithalat listesini de eklediğiniz için teşekkürler, aksi takdirde gerekli kombinasyonu anlamlandırmak için çok sayıda çakışan paket mevcut ..
Leon

54

Sadece en yüksek puanlı cevabın xerces kullanımını gerektirdiğini unutmayın.

Bu harici bağımlılığı eklemek istemiyorsanız, standart jdk kitaplıklarını (aslında xerces dahili olarak kullanılarak oluşturulur) kullanabilirsiniz.

Not jdk 1.5 sürümünde bir hata oluştu bkz. Http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6296446 ama şimdi çözüldü.,

(Bir hata oluşursa orijinal metnin döndürüleceğini unutmayın)

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(String[] args) {
        XmlTest t = new XmlTest();
        System.out.println(t.formatXml("<a><b><c/><d>text D</d><e value='0'/></b></a>"));
    }

    public String formatXml(String 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 String(((ByteArrayOutputStream)res.getOutputStream()).toByteArray());
        }catch(Exception e){
            //TODO log error
            return xml;
        }
    }

}

Bu durumda sol sekmeler kullanılmaz. Tüm etiketler, normal metin gibi satırın ilk sembolünden başlar.
Ruslan

bayt ve dize arasında geçiş yaparken bir karakter kümesi belirtmeniz gerekmez mi?
Will Glass

2
Dizilerden / Bayt dizilerine dönüştürmeye ve Dizeye dönüştürmeye gerek olmamalıdır. En azından bunu yaparken charset belirtmelisiniz. InputSource ve StreamResult içine sarılmış StringReader ve StringWriter sınıflarını kullanmak daha iyi bir seçenek olabilir.
maximdim

çalışmıyor. bazı iç kayıt defteri uygulaması ile uğraşmak gerekir.
user1050755

İşte bu çözümün daha basit bir çeşidi: stackoverflow.com/a/33541820/363573
Stephan

32

Oldukça org.dom4j.io.OutputFormat.createPrettyPrint () yöntemini kullanarak yazdırdım

public String prettyPrint(final String xml){  

    if (StringUtils.isBlank(xml)) {
        throw new RuntimeException("xml was null or blank in prettyPrint()");
    }

    final StringWriter sw;

    try {
        final OutputFormat format = OutputFormat.createPrettyPrint();
        final org.dom4j.Document document = DocumentHelper.parseText(xml);
        sw = new StringWriter();
        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.toString();
}

3
Kabul edilen çözüm, benim durumumda yuvalanmış etiketleri düzgün bir şekilde girintili değil, bu.
Chase Seibert

3
Ben satır sonunda tüm sondaki boşlukları kaldırmak ile birlikte bunu kullandım:prettyPrintedString.replaceAll("\\s+\n", "\n")
jediz

19

İşte dom4j kullanarak yapmanın bir yolu :

İthalat:

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

Kod:

String xml = "<your xml='here'/>";  
Document doc = DocumentHelper.parseText(xml);  
StringWriter sw = new StringWriter();  
OutputFormat format = OutputFormat.createPrettyPrint();  
XMLWriter xw = new XMLWriter(sw, format);  
xw.write(doc);  
String result = sw.toString();

1
Bu benim için işe yaramadı. Sadece şöyle bir şey verdi: <?xml version...bir satırda ve diğer her şey başka bir satırda.
sixtyfootersdude

14

A ile başladığınız için, öğesini kullanmadan önce Stringbir DOMnesneye (örn. Node) Geçmeniz gerekir Transformer. Bununla birlikte, XML dizenizin geçerli olduğunu biliyorsanız ve bir dizeyi DOM'ye ayrıştırmak için bellek ek yüküne maruz kalmak istemiyorsanız, daha sonra bir dizeyi geri almak için DOM üzerinde bir dönüşüm çalıştırın - eski moda bir şeyler yapabilirsiniz karakter ayrıştırma. Her </...>karakterden sonra bir satırsonu ve boşluk ekleyin , her biri için artırdığınız sayacı (boşluk sayısını belirlemek için) tutun ve girin <...>ve </...>gördüğünüz her sayı için azaltın .

Yasal Uyarı - Aşağıdaki işlevlerin bir kesme / yapıştırma / metin düzenleme yaptım, bu yüzden olduğu gibi derlemek olmayabilir.

public static final Element createDOM(String strXML) 
    throws ParserConfigurationException, SAXException, IOException {

    DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
    dbf.setValidating(true);
    DocumentBuilder db = dbf.newDocumentBuilder();
    InputSource sourceXML = new InputSource(new StringReader(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));
}

1
"Ancak, XML dizenizin geçerli olduğunu biliyorsanız ..." iyi bir nokta. Aşağıdaki bu yaklaşıma dayalı çözümümü görün.
David Easley

12

3. taraf bir XML kitaplığı kullanmak uygunsa, şu anda en çok oy alan cevapların önerdiğinden çok daha basit bir şeyden kurtulabilirsiniz .

Hem girdi hem de çıktının Dizeler olması gerektiği belirtildi, bu yüzden XOM kütüphanesi ile uygulanan bunu yapan bir yardımcı yöntem :

import nu.xom.*;
import java.io.*;

[...]

public static String format(String 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.toString("UTF-8");
}

Çalıştığını test ettim ve sonuçlar JRE sürümünüze veya bunun gibi bir şeye bağlı değil . Çıktı biçimini beğeninize göre nasıl özelleştireceğinizi görmek için SerializerAPI'ya bakın.

Bu aslında düşündüğümden daha uzun çıktı - bazı ekstra satırlara ihtiyaç duyuldu çünkü yazmak Serializeristiyor OutputStream. Ancak burada gerçek XML döndürme için çok az kod olduğunu unutmayın.

(Bu cevap oldu XOM benim değerlendirmenin bir parçasıdır önerdi benim tek seçenek olarak iyi Java XML kitaplığı hakkında soru dom4j yerine Kayıt için, dom4j ile benzer kolaylığı kullanarak bunu başarabilir. XMLWriterVe OutputFormat. Düzenleme : .. mlo55'in cevabında gösterildiği gibi .)


2
Teşekkürler, aradığım şey bu. "Belge" nesnesinde zaten XOM ile ayrıştırılmış bir XML'niz varsa, bunu doğrudan serializer.write (document) öğesine iletebilirsiniz;
Thibault D.

12

Kevin Hakanson şöyle dedi: "Ancak, XML dizenizin geçerli olduğunu biliyorsanız ve bir dizeyi bir DOM'a ayrıştırmanın bellek yükünü artırmak istemiyorsanız, daha sonra bir dizeyi geri almak için DOM üzerinde bir dönüşüm gerçekleştirebilirsiniz. sadece karakter ayrıştırma ile bazı eski moda karakterleri yapın. Her karakterden sonra bir satırsonu ve boşluk ekleyin, her <...> için arttıracağınız sayacı (boşluk sayısını belirlemek için) ve girinti ve gördüğünüz her bir azalma için girin. "

Kabul. Böyle bir yaklaşım çok daha hızlıdır ve çok daha az bağımlılığı vardır.

Örnek çözüm:

/**
 * XML utils, including formatting.
 */
public class XmlUtils
{
  private static XmlFormatter formatter = new XmlFormatter(2, 80);

  public static String formatXml(String s)
  {
    return formatter.format(s, 0);
  }

  public static String formatXml(String 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 String format(String s, int initialIndent)
    {
      int indent = initialIndent;
      StringBuilder sb = new StringBuilder();
      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)
            {
              String textBetweenElements = s.substring(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.substring(lineStartPos, lineEndPos + 1));
      lineStartPos = lineEndPos + 1;
    }
    return sb.toString();
  }

  // other utils removed for brevity
}

2
Bu böyle yapılmalı. Dize düzeyinde anında biçimlendirin. Geçersiz veya eksik XML'yi biçimlendirecek tek çözüm budur.
Florian F

11

Hmmm ... böyle bir şeyle karşılaştı ve bilinen bir hatadır ... sadece bu OutputProperty'yi ekleyin ..

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

Bu yardımcı olur umarım ...


2
Bu OutputPropertiesFactory nereden geliyor?
helenov

import com.sun.org.apache.xml.internal.serializer. *;
gaurav

9

"Önce bir DOM ağacı oluşturmanız gerekir" yorumuyla ilgili olarak: Hayır, buna ihtiyacınız yoktur ve olmamalıdır.

Bunun yerine, bir StreamSource (yeni StreamSource (yeni StringReader (str)) oluşturun ve bunu belirtilen kimlik transformatörüne besleyin. SAX ayrıştırıcısını kullanacak ve sonuç çok daha hızlı olacaktır. Aksi halde üst düzey cevap iyidir.


1
Ben yürekten katılıyorum: ara DOM ağacını inşa etmek bir hafıza kaybıdır. Bu cevap için Thansk.
Florian F

9

Scala kullanma:

import xml._
val xml = XML.loadString("<tag><nested>hello</nested></tag>")
val formatted = new PrettyPrinter(150, 2).format(xml)
println(formatted)

Scala-library.jar dosyasına bağlıysanız, bunu Java'da da yapabilirsiniz. Şöyle görünüyor:

import scala.xml.*;

public class FormatXML {
    public static void main(String[] args) {
        String unformattedXml = "<tag><nested>hello</nested></tag>";
        PrettyPrinter pp = new PrettyPrinter(150, 3);
        String formatted = pp.format(XML.loadString(unformattedXml), TopScope$.MODULE$);
        System.out.println(formatted);
    }
}

PrettyPrinterNesnenin iki ints, ilk olarak maksimum çizgi uzunluğu ve girinti adımı olan ikinci ile inşa edilmiştir.


9

milosmenlerden biraz geliştirilmiş versiyon ...

public static String getPrettyXml(String xml) {
    if (xml == null || xml.trim().length() == 0) return "";

    int stack = 0;
    StringBuilder pretty = new StringBuilder();
    String[] rows = xml.trim().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("<?")) {
            pretty.append(row + "\n");
        } else if (row.startsWith("</")) {
            String indent = repeatString(--stack);
            pretty.append(indent + row + "\n");
        } else if (row.startsWith("<") && row.endsWith("/>") == false) {
            String indent = repeatString(stack++);
            pretty.append(indent + row + "\n");
            if (row.endsWith("]]>")) stack--;
        } else {
            String indent = repeatString(stack);
            pretty.append(indent + row + "\n");
        }
    }

    return pretty.toString().trim();
}

private static String repeatString(int stack) {
     StringBuilder indent = new StringBuilder();
     for (int i = 0; i < stack; i++) {
        indent.append(" ");
     }
     return indent.toString();
} 

burada repeatString (yığın ++); yöntem..?
user1912935

2
private static Dize repeatString (int stack) {StringBuilder indent = yeni StringBuilder (); for (int i = 0; i <yığın; i ++) {indent.append (""); } dönüş indent.toString (); }
codeskraps

Girinti uç etiketlerinde iyi çalışmıyor } else if (row.startsWith("</")) {. Bunun bir kısmını değiştirmeniz gerekiyor :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"); } }
Csaba Tenkes

8

Sadece ileride başvurmak için, benim için çalışan bir çözüm (@George Hawkins'in cevaplardan birinde yayınladığı bir yorum sayesinde):

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);
String xmlStr = new String(out.toByteArray());

6

Geçerli bir XML'ye sahip olduğunuzdan eminseniz, bu basittir ve XML DOM ağaçlarından kaçınır. Belki bazı hatalar vardır, bir şey görürseniz yorum yapın

public String prettyPrint(String xml) {
            if (xml == null || xml.trim().length() == 0) return "";

            int stack = 0;
            StringBuilder pretty = new StringBuilder();
            String[] rows = xml.trim().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("<?")) {
                            // xml version tag
                            pretty.append(row + "\n");
                    } else if (row.startsWith("</")) {
                            // closing tag
                            String indent = repeatString("    ", --stack);
                            pretty.append(indent + row + "\n");
                    } else if (row.startsWith("<")) {
                            // starting tag
                            String indent = repeatString("    ", stack++);
                            pretty.append(indent + row + "\n");
                    } else {
                            // tag data
                            String indent = repeatString("    ", stack);
                            pretty.append(indent + row + "\n");
                    }
            }

            return pretty.toString().trim();
    }

2
repeatString yöntemi nerede ..?
user1912935

3
private static Dize repeatString (int stack) {StringBuilder indent = yeni StringBuilder (); for (int i = 0; i <yığın; i ++) {indent.append (""); } dönüş indent.toString (); }
codeskraps

Evet [user1912935], @codeskraps'ın yazdığı şey, yeterince basit olmalı :)
milosmns

Döngü içindeki StringBuilder ile birleştirme: Kötü uygulama.
james.garriss

@ james.garriss Ancak yeni hatlara bölmek çok kolay, bu sadece DOM ağaçları olmadan basit bir yaklaşımı gösteriyor.
milosmlar

5

Yukarıdaki tüm çözümler benim için işe yaramadı, sonra bunu buldum http://myshittycode.com/2014/02/10/java-properly-indenting-xml-string/

İpucu XPath ile boşlukları kaldırmak

    String xml = "<root>" +
             "\n   " +
             "\n<name>Coco Puff</name>" +
             "\n        <total>10</total>    </root>";

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

1
'{ Xml.apache.org/xslt } girinti miktarı' özelliğinin kullanımının sizi belirli bir trafo uygulamasına bağlayacağını unutmayın.
vallismortis

1
Tüm çözümlerden bu en iyi sonucu verdi. XML'imde boşluklar ve yeni satırlar vardı, ayrıca projeme daha fazla bağımlılık eklemek istemedim. Keşke XML ayrıştırmak zorunda değildi ama oh iyi.
Fabio

5

Aşağıdaki bu kod mükemmel çalışıyor

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;

String formattedXml1 = prettyFormat("<root><child>aaa</child><child/></root>");

public static String prettyFormat(String input) {
    return prettyFormat(input, "2");
}

public static String prettyFormat(String input, String indent) {
    Source xmlInput = new StreamSource(new StringReader(input));
    StringWriter stringWriter = new StringWriter();
    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(stringWriter));

        String pretty = stringWriter.toString();
        pretty = pretty.replace("\r\n", "\n");
        return pretty;              
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}

5

Hepsini karıştırıp küçük bir program yazıyorum. Bu xml dosyasından okuma ve çıktı. Sadece xzy yerine dosya yolunuzu verin.

    public static void main(String[] args) throws Exception {
    DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
    dbf.setValidating(false);
    DocumentBuilder db = dbf.newDocumentBuilder();
    Document doc = db.parse(new FileInputStream(new File("C:/Users/xyz.xml")));
    prettyPrint(doc);

}

private static String prettyPrint(Document document)
        throws TransformerException {
    TransformerFactory transformerFactory = TransformerFactory
            .newInstance();
    Transformer transformer = transformerFactory.newTransformer();
    transformer.setOutputProperty(OutputKeys.INDENT, "yes");
    transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
    transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
    transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
    DOMSource source = new DOMSource(document);
    StringWriter strWriter = new StringWriter();
    StreamResult result = new StreamResult(strWriter);transformer.transform(source, result);
    System.out.println(strWriter.getBuffer().toString());

    return strWriter.getBuffer().toString();

}

4

Bizim için çalışan başka bir çözüm

import java.io.StringWriter;
import org.dom4j.DocumentHelper;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.XMLWriter;

**
 * Pretty Print XML String
 * 
 * @param inputXmlString
 * @return
 */
public static String prettyPrintXml(String xml) {

    final StringWriter sw;

    try {
        final OutputFormat format = OutputFormat.createPrettyPrint();
        final org.dom4j.Document document = DocumentHelper.parseText(xml);
        sw = new StringWriter();
        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.toString();
}

3

Jdom2'yi kullanma: http://www.jdom.org/

import java.io.StringReader;
import org.jdom2.input.SAXBuilder;
import org.jdom2.output.Format;
import org.jdom2.output.XMLOutputter;

String prettyXml = new XMLOutputter(Format.getPrettyFormat()).
                         outputString(new SAXBuilder().build(new StringReader(uglyXml)));

3

Max , codekraps , David Easley ve milosmların cevaplarına alternatif olarak, hafif, yüksek performanslı güzel yazıcı kütüphaneme bir göz atın: xml-formatter

// construct lightweight, threadsafe, instance
PrettyPrinter prettyPrinter = PrettyPrinterBuilder.newPrettyPrinter().build();

StringBuilder buffer = new StringBuilder();
String xml = ..; // also works with char[] or Reader

if(prettyPrinter.process(xml, buffer)) {
     // valid XML, print buffer
} else {
     // invalid XML, print xml
}

Bazen, alaycı SOAP hizmetlerini doğrudan dosyadan çalıştırırken olduğu gibi, zaten güzel yazdırılmış XML'i de işleyen güzel bir yazıcıya sahip olmak iyidir:

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

Bazılarının yorumladığı gibi, güzel baskı, XML'i daha insan tarafından okunabilir bir şekilde sunmanın bir yoludur - boşluk kesinlikle XML verilerinize ait değildir.

Kütüphane, günlük kaydı amacıyla güzel yazdırma için tasarlanmıştır ve ayrıca filtreleme (alt ağaç kaldırma / anonimleştirme) ve XML'nin CDATA ve Metin düğümlerinde güzel yazdırılması işlevlerini içerir.


2

Aynı sorunu yaşadım ve JTidy ile büyük başarı elde ediyorum ( http://jtidy.sourceforge.net/index.html )

Misal:

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);
String html = out.toString();

2

Alt çizgi-java statik bir yönteme sahiptir U.formatXml(string). Ben projenin koruyucusuyum. Canlı örnek

import com.github.underscore.lodash.U;

public class MyClass {
    public static void main(String args[]) {
        String xml = "<tag><nested>hello</nested></tag>";

        System.out.println(U.formatXml("<?xml version=\"1.0\" encoding=\"UTF-8\"?><root>" + xml + "</root>"));
    }
}

Çıktı:

<?xml version="1.0" encoding="UTF-8"?>
<root>
   <tag>
      <nested>hello</nested>
   </tag>
</root>

Bu harika!
senyor

1

xmlstarlet ( http://xmlstar.sourceforge.net/ ) adında bir çok insanın kullandığı birçok şeyi yapabilen çok güzel bir komut satırı xml yardımcı programı var .

Bu programı Runtime.exec kullanarak programlı olarak çalıştırabilir ve sonra biçimlendirilmiş çıktı dosyasını okuyabilirsiniz. Birkaç Java kodu satırından daha fazla seçenek ve daha iyi hata raporlaması vardır.

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


1

Java 1.6.0_32'de güzel bir XML dizesi yazdırmak için normal bir yöntem (boş veya kimliğe sahip bir transformatör kullanarak xslt) etiketleri ayırmak yerine, yalnızca boşlukla ayrılırsa istediğim gibi davranmadığını buldum Metin. <xsl:strip-space elements="*"/>Şablonumda boşuna kullanmayı denedim . Bulduğum en basit çözüm, alanı bir SAXSource ve XML filtresi kullanarak istediğim şekilde çıkarmaktı. Çözümüm günlüğe kaydetme için olduğundan, eksik XML parçalarıyla çalışmak için bunu genişlettim. Bir DOMSource kullanıyorsanız normal yöntem iyi çalışıyor gibi görünüyor, ancak eksiklik ve bellek ek yükü nedeniyle bunu kullanmak istemiyordu.

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 String(ch, start, length).trim().equals("")) 
               super.characters(ch, start, length); 
    }
}

public static String prettyXML(String logMsg, boolean allowBadlyFormedFragments) throws SAXException, IOException, TransformerException
    {
        TransformerFactory transFactory = TransformerFactory.newInstance();
        transFactory.setAttribute("indent-number", new Integer(2));
        Transformer transformer = transFactory.newTransformer();
        transformer.setOutputProperty(OutputKeys.INDENT, "yes");
        transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
        StringWriter out = new StringWriter();
        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 StringReader(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.toString();
    }

1

Java 1.6+ için burada bulduğum çözümler, biçimlendirilmişse kodu yeniden biçimlendirmez. Benim için çalışan (ve zaten biçimlendirilmiş kodu yeniden biçimlendirilmiş) aşağıdaki idi.

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.StringReader;

public class XmlUtils {
    public static String toCanonicalXml(String 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 String(canonXmlBytes);
    }

    public static String prettyFormat(String input) throws TransformerException, ParserConfigurationException, IOException, SAXException, InstantiationException, IllegalAccessException, ClassNotFoundException {
        InputSource src = new InputSource(new StringReader(input));
        Element document = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(src).getDocumentElement();
        Boolean keepDeclaration = input.startsWith("<?xml");
        DOMImplementationRegistry registry = DOMImplementationRegistry.newInstance();
        DOMImplementationLS impl = (DOMImplementationLS) registry.getDOMImplementation("LS");
        LSSerializer writer = impl.createLSSerializer();
        writer.getDomConfig().setParameter("format-pretty-print", Boolean.TRUE);
        writer.getDomConfig().setParameter("xml-declaration", keepDeclaration);
        return writer.writeToString(document);
    }
}

Tam dize xml karşılaştırması için birim testlerinizde kullanmak için iyi bir araçtır.

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

1

XML'nin% 100 geçerli olması gerekmeyen hızlı ve kirli bir çözüm arayanlar için. REST / SOAP kaydı durumunda (başkalarının ne gönderdiğini asla bilemezsiniz ;-))

Ben burada geçerli bir olası yaklaşım olarak eksik olduğunu düşünüyorum çevrimiçi bulundu buldum ve snipped bir kod gelişmiş:

public static String prettyPrintXMLAsString(String xmlString) {
    /* Remove new lines */
    final String LINE_BREAK = "\n";
    xmlString = xmlString.replaceAll(LINE_BREAK, "");
    StringBuffer prettyPrintXml = new StringBuffer();
    /* Group the xml tags */
    Pattern pattern = Pattern.compile("(<[^/][^>]+>)?([^<]*)(</[^>]+>)?(<[^/][^>]+/>)?");
    Matcher matcher = pattern.matcher(xmlString);
    int tabCount = 0;
    while (matcher.find()) {
        String str1 = (null == matcher.group(1) || "null".equals(matcher.group())) ? "" : matcher.group(1);
        String str2 = (null == matcher.group(2) || "null".equals(matcher.group())) ? "" : matcher.group(2);
        String str3 = (null == matcher.group(3) || "null".equals(matcher.group())) ? "" : matcher.group(3);
        String str4 = (null == matcher.group(4) || "null".equals(matcher.group())) ? "" : matcher.group(4);

        if (matcher.group() != null && !matcher.group().trim().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.toString();
}

private static void printTabs(int count, StringBuffer stringBuffer) {
    for (int i = 0; i < count; i++) {
        stringBuffer.append("\t");
    }
}

public static void main(String[] args) {
    String x = new String(
            "<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\"><soap:Body><soap:Fault><faultcode>soap:Client</faultcode><faultstring>INVALID_MESSAGE</faultstring><detail><ns3:XcbSoapFault xmlns=\"\" xmlns:ns3=\"http://www.someapp.eu/xcb/types/xcb/v1\"><CauseCode>20007</CauseCode><CauseText>INVALID_MESSAGE</CauseText><DebugInfo>Problems creating SAAJ object model</DebugInfo></ns3:XcbSoapFault></detail></soap:Fault></soap:Body></soap:Envelope>");
    System.out.println(prettyPrintXMLAsString(x));
}

İşte çıktı:

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Body>
    <soap:Fault>
        <faultcode>soap:Client</faultcode>
        <faultstring>INVALID_MESSAGE</faultstring>
        <detail>
            <ns3:XcbSoapFault xmlns="" xmlns:ns3="http://www.someapp.eu/xcb/types/xcb/v1">
                <CauseCode>20007</CauseCode>
                <CauseText>INVALID_MESSAGE</CauseText>
                <DebugInfo>Problems creating SAAJ object model</DebugInfo>
            </ns3:XcbSoapFault>
        </detail>
    </soap:Fault>
  </soap:Body>
</soap:Envelope>

1

Kullanarak bir cevap gördüm Scala, işte Groovybirisinin ilginç bulması durumunda başka bir cevap daha . Varsayılan girinti 2 adımdır, XmlNodePrinteryapıcı da başka bir değer geçirilebilir.

def xml = "<tag><nested>hello</nested></tag>"
def stringWriter = new StringWriter()
def node = new XmlParser().parseText(xml);
new XmlNodePrinter(new PrintWriter(stringWriter)).print(node)
println stringWriter.toString()

Groovy jar sınıf yolundaysa Java'dan kullanım

  String xml = "<tag><nested>hello</nested></tag>";
  StringWriter stringWriter = new StringWriter();
  Node node = new XmlParser().parseText(xml);
  new XmlNodePrinter(new PrintWriter(stringWriter)).print(node);
  System.out.println(stringWriter.toString());

1

O kadar çok girintiye ihtiyacınız yoksa, ancak birkaç satır kırılırsa, basit bir şekilde normal ifadeyi kullanmak yeterli olabilir ...

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

Kod güzel, eksik girinti sonucu değil.


(Girintili çözümler için diğer yanıtlara bakın.)


1
Hmmmm ... Sadece yüksek sesle düşünmek, kimin böyle bir çözüme ihtiyacı var? Görebildiğim tek alan, bazı web servislerinden aldığımız verilerdir ve sadece verilerin ve geçerliliğinin, geliştiricisinin veya test cihazının bu kadar kolay olanlara ihtiyacı olabileceğini test etmek için. Aksi takdirde iyi bir seçenek değil ....
Sudhakar Chavali

1
@SudhakarChavali Ben bir geliştiriciyim. kirli println () ve log.debug () kesmek için gerekebilir; yani bazen i sadece adım adım hata ayıklama programı yerine aklı başında (sadece kabuk erişim yerine web yönetici arayüzü ile) sadece sunucu dosyaları günlük dosyalarını kullanabilirsiniz.
comonad
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.