Java에서 XML을 예쁘게 인쇄하는 방법은 무엇입니까?


443

줄 바꿈이나 들여 쓰기가없는 XML이 포함 된 Java String이 있습니다. 멋진 형식의 XML을 사용하여 String으로 바꾸고 싶습니다. 어떻게해야합니까?

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

참고 : 내 입력은 String 입니다. 내 출력은 String 입니다.

(기본) 모의 결과 :

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

이 질문을 확인하십시오 : stackoverflow.com/questions/1264849/…
dfa

10
궁금한 점이 있다면,이 출력을 XML 파일이나 들여 쓰기가 중요한 다른 곳으로 보내십니까? 얼마 전에 XML을 올바르게 표시하기 위해 XML 형식을 설정하는 데 매우 관심이 있었지만 이것에 많은 시간을 보낸 후 출력을 웹 브라우저 및 비교적 현대적인 웹 브라우저로 보내야한다는 것을 깨달았습니다. 실제로 멋진 트리 구조로 XML을 표시 하므로이 문제를 잊어 버릴 수 있습니다. 나는 당신 (또는 같은 문제를 가진 다른 사용자)이 동일한 세부 사항을 간과 할 수있는 경우를 대비하여 이것을 언급하고 있습니다.
Abel Morelos

3
@Abel, 텍스트 파일로 저장, HTML 텍스트 영역에 삽입 및 디버깅 목적으로 콘솔에 덤프.
Steve McLeod

2
"너무 광범위하게 보류"-현재 질문보다 더 정확한 것은 어렵습니다!
Steve McLeod

답변:


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

참고 : 결과는 Java 버전에 따라 다를 수 있습니다. 플랫폼과 관련된 해결 방법을 검색하십시오.


1
출력에 포함되지 않도록 만드는 방법은 <?xml version="1.0" encoding="UTF-8"?>무엇입니까?
Thang Pham

19
<?xml ...>선언 을 생략하려면transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes")
Rusyx

4
일반 독자는 여기에 설명 된 솔루션의 개선 된 버전 ( stackoverflow.com/a/33541820/363573 )을 유용하게 사용할 수 있습니다 .
Stephan

5
어디에 doc정의되어 있습니까?
Florian F

6
이것은 내 질문에 대답하지 않습니다 : XML이 포함 된 문자열을 어떻게 포맷합니까? 이 답변은 이미 String 객체를 다른 객체로 변환했다고 가정합니다.
Steve McLeod

135

여기 내 질문에 대한 답변이 있습니다. 다양한 결과의 답변을 결합하여 XML을 예쁘게 인쇄하는 클래스를 작성했습니다.

유효하지 않은 XML 또는 큰 문서로 응답하는 방식에 대해 보증하지 않습니다.

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
이 답변에는 Xerces를 사용해야합니다. 이 의존성을 추가하지 않으려면 표준 jdk 라이브러리와 javax.xml.transform.Transformer를 사용하면됩니다 (아래 답변 참조)
khylo

45
2008 년에 이것은 좋은 대답 이었지만 이제는 Apache 클래스가 아닌 표준 JDK 클래스로 수행 할 수 있습니다. xerces.apache.org/xerces2-j/faq-general.html#faq-6을 참조하십시오 . 예, 이것은 Xerces FAQ이지만 표준 JDK 클래스에 대한 답변입니다. 이 클래스의 초기 1.5 구현에는 많은 문제가 있었지만 모든 것이 1.6부터 잘 작동합니다. FAQ에서 LSSerializer 예제를 복사하고 "..."비트를 잘라 라인 writer.getDomConfig().setParameter("format-pretty-print", Boolean.TRUE);뒤에 추가 하십시오 LSSerializer writer = ....
George Hawkins

2
@GeorgeHawkins가 링크 한 Apache의 예제를 사용하여 작은 클래스를 만들었습니다. 변수 document가 초기화되는 방법이 누락 되었으므로 감속을 추가하고 빠른 예를 만들 수 있다고 생각했습니다. 내가 뭔가 변화해야하는지 알려주세요 pastebin.com/XL7932aC을
샘웰

jdk로만 할 수 있다는 것은 사실이 아닙니다. 적어도 확실하지 않습니다. 기본적으로 jdk7u72에서 활성화되지 않은 일부 내부 레지스트리 구현에 따라 다릅니다. 아파치 도구를 직접 사용하는 것이 좋습니다.
user1050755

다음은 종속성이없는 솔루션입니다. stackoverflow.com/a/33541820/363573 .
Stephan

131

이 답변을 기반으로 한 간단한 솔루션 :

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

테스트 케이스 :

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

보고:

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

1
이것은 내가 항상 사용했던 코드이지만이 회사에서는 작동하지 않았습니다. 다른 XML 변환 라이브러리를 사용한다고 가정합니다. 공장을 별도의 줄로 만든 다음 factory.setAttribute("indent-number", 4);작동했으며 이제는 작동합니다.
Adrian Smith

출력에 포함되지 않도록 만드는 방법은 <?xml version="1.0" encoding="UTF-8"?>무엇입니까?
Thang Pham

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

5
안녕하세요,이 정확한 코드를 사용하고 있으며 첫 번째 요소를 제외하고 올바르게 형식을 지정합니다. 그래서 이것은 <?xml version="1.0" encoding="UTF-8"?><root>모두 한 줄에 있습니다. 어떤 아이디어가 있습니까?
CodyK

2
@Codemiester : 버그 인 것 같습니다 ( stackoverflow.com/a/18251901/3375325 참조 ). 추가 transformer.setOutputProperty(OutputKeys.DOCTYPE_PUBLIC, "yes");는 나를 위해 일했습니다.
jansohn

100

이제는 2012 년이며 Java는 XML보다 이전보다 더 많은 일을 할 수 있습니다. 허용 된 답변에 대안을 추가하고 싶습니다. 이것은 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.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));
    }
}

들여 쓰기는 없지만 다음과 같이 작동합니다. System.setProperty (DOMImplementationRegistry.PROPERTY, "com.sun.org.apache.xerces.internal.dom.DOMImplementationSourceImpl");
ggb667

1
이 예제에 어떻게 들여 쓰기를 추가합니까?
ggb667

2
@DanTemple 인코딩을 제어하려면 LSOutput을 사용해야 할 것 같습니다. 참조 chipkillmar.net/2009/03/25/pretty-print-xml-from-a-dom
조슈아 데이비스

1
Andriod에서 이것을 사용하려고했지만`DOMImplementationRegistry 패키지를 찾을 수 없습니다. 나는 자바 8을 사용하고 있습니다.
Chintan Soni

2
가져 오기 목록도 포함 해 주셔서 감사합니다. 다른 방법으로 필요한 조합을 이해하기 위해 많은 상충되는 패키지를 사용할 수 있습니다.
Leon

54

최고 등급의 답변에는 xerces를 사용해야합니다.

이 외부 종속성을 추가하지 않으려는 경우 표준 jdk 라이브러리 (실제로 xerces를 사용하여 내부적으로 빌드 됨)를 사용하면됩니다.

NB jdk 버전 1.5에 버그가 발생 했습니다 ( http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6296446 참조) .

(오류가 발생하면 원본 텍스트를 반환합니다)

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

}

이 경우 왼쪽 탭은 사용되지 않습니다. 모든 태그는 일반적인 텍스트와 같이 줄의 첫 번째 기호에서 시작합니다.
Ruslan

바이트와 ​​문자열 사이에서 앞뒤로 변환 할 때 문자 집합을 지정할 필요가 없습니까?
Will Glass

2
바이트 배열 / 문자열을 변환 할 필요가 없습니다. 최소한 그렇게 할 때 charset을 지정해야합니다. 더 나은 옵션은 InputSource 및 StreamResult로 래핑 된 StringReader 및 StringWriter 클래스를 사용하는 것입니다.
maximdim

작동하지 않는. 내부 레지스트리 구현을 엉망으로 만들어야합니다.
user1050755

이 솔루션의 더 간단한 변형은 다음과 같습니다. stackoverflow.com/a/33541820/363573
Stephan

32

과거에는 org.dom4j.io.OutputFormat.createPrettyPrint () 메소드를 사용하여 꽤 인쇄했습니다.

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
허용 된 솔루션은 내 경우에 중첩 된 태그를 올바르게 들여 쓰기하지 않습니다.
체이스 세이버 트

3
: I 라인의 끝에서 모든 후행 공백을 제거와 연동 해이 사용prettyPrintedString.replaceAll("\\s+\n", "\n")
jediz을

19

dom4j를 사용하여 수행하는 방법은 다음과 같습니다 .

수입품 :

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

암호:

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
이것은 나를 위해 작동하지 않았다. 그것은 <?xml version...한 줄과 다른 줄의 모든 것을 제공했습니다.
sixtyfootersdude

14

로 시작 String하기 때문에을 (를 ) 사용하려면 먼저 DOM객체 (예 :)를 숨겨야 Node합니다 Transformer. 그러나 XML 문자열이 유효하다는 것을 알고 문자열을 DOM으로 구문 분석하는 데 메모리 오버 헤드가 발생하지 않게하려면 DOM에서 변환을 실행하여 문자열을 다시 가져 오십시오. 문자 별 분석. 모든 </...>문자 다음에 줄 바꿈과 공백을 삽입하고 , 매번 증가 <...>하고 감소하는 카운터 (공백 수를 결정하기 위해)를 들여 쓰기하십시오.</...> 당신이 볼.

면책 조항-아래 기능을 잘라 내기 / 붙여 넣기 / 텍스트 편집을 했으므로 그대로 컴파일되지 않을 수 있습니다.

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
"하지만 XML 문자열이 유효하다는 것을 안다면 ..."좋은 지적입니다. 아래 의이 접근법을 기반으로 내 솔루션을 참조하십시오.
David Easley

12

써드 파티 XML 라이브러리를 사용해도 괜찮다면, 현재 가장 많이 투표 된 답변이 제시 하는 것보다 훨씬 간단한 것을 피할 수 있습니다.

입력과 출력이 모두 문자열이어야한다고 언급되었으므로 XOM 라이브러리로 구현 된 유틸리티 메소드는 다음과 같습니다.

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

나는 그것이 작동하는지 테스트했으며 결과 JRE 버전이나 그와 같은 것에 의존 하지 않습니다 . 원하는대로 출력 형식을 사용자 정의하는 방법을 보려면Serializer API를 .

이것은 실제로 내가 생각했던 것보다 더 오래 나왔습니다 Serializer.OutputStream . 쓰기를 했습니다. 그러나 실제 XML twiddling에 대한 코드는 거의 없습니다.

(이 답변했다 XOM의 내 평가의 일부입니다 제안 내에서 하나의 옵션으로 최고의 자바 XML 라이브러리에 대한 질문 DOM4J를 대체 할 수있는 기록을 위해, DOM4J와 비슷한 용이성 사용하여이를 달성 할 수있다. XMLWriterOutputFormat. 편집 .. .mlo55의 답변나와 있는 것처럼 .)


2
고마워, 내가 찾던거야. "Document"객체에서 XOM으로 XML을 이미 구문 분석 한 경우 serializer.write (document)에 직접 전달할 수 있습니다.
Thibault D.

12

Kevin Hakanson은 "그러나 XML 문자열이 유효하다는 것을 알고 문자열을 DOM으로 구문 분석 한 다음 DOM을 통해 변환을 실행하여 문자열을 다시 가져 오는 메모리 오버 헤드가 발생하지 않도록하려면 모든 문자 뒤에 줄 바꿈과 공백을 삽입하고, 모든 <...>마다 증가하는 카운터 (공백 수를 결정하기 위해 들여 쓰기)를 들여 쓰고 들여 쓰기마다 줄이십시오. "

동의했다. 이러한 접근 방식은 훨씬 빠르며 종속성이 훨씬 적습니다.

솔루션 예 :

/**
 * 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
이것이 수행되어야하는 방법입니다. 문자열 수준에서 즉시 형식을 지정하십시오. 이것은 유효하지 않거나 불완전한 XML을 포맷하는 유일한 솔루션입니다.
Florian F

11

흠 ...이 같은 것을 직면하고 알려진 버그입니다 ... 그냥이 OutputProperty 추가하십시오 ..

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

도움이 되었기를 바랍니다 ...


2
이 OutputPropertiesFactory는 어디에서 왔습니까?
helenov 2016 년

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

9

"먼저 DOM 트리를 빌드해야합니다"라는 의견에 대해 : 아니오, 그렇지 않아도됩니다.

대신 StreamSource (new StreamSource (new StringReader (str)))를 만들어 언급 된 자격 증명 변환기에 공급하면 SAX 파서를 사용하므로 결과가 훨씬 빨라집니다.이 경우 중간 트리를 작성하는 것이 순수한 오버 헤드입니다. 그렇지 않으면 최상위 답변이 좋습니다.


1
나는 진심으로 동의합니다 : 중간 DOM 트리를 만드는 것은 메모리 낭비입니다. 그 대답에 감사드립니다.
Florian F

9

스칼라 사용 :

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

scala-library.jar에 의존하는 경우 Java에서도이를 수행 할 수 있습니다. 다음과 같이 보입니다 :

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

PrettyPrinter목적은 두하는 int, 제 인 최대 광고 길이 압입 단계와 상기 제 2 구성된다.


9

milosmns 에서 약간 개선 된 버전 ...

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

repeatString (stack ++)은 어디에 있습니까? 방법..?
user1912935 2016 년

2
private static String repeatString (int stack) {StringBuilder indent = 새로운 StringBuilder (); for (int i = 0; i <stack; i ++) {indent.append ( ""); } indent.toString ()을 반환합니다. }
코드 크랩

끝 태그에서 들여 쓰기가 제대로 작동하지 않습니다. } else if (row.startsWith("</")) {부분을 ​​다음과 같이 변경해야합니다 .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

나중에 참조 할 수 있도록 다음과 같은 솔루션이 있습니다 (@George Hawkins가 답변 중 하나를 게시 한 의견 덕분에).

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

유효한 XML이 있다고 확신하는 경우 간단하고 XML DOM 트리를 피할 수 있습니다. 버그가있을 수 있습니다.

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 메소드는 어디에 있습니까?
user1912935

3
private static String repeatString (int stack) {StringBuilder indent = 새로운 StringBuilder (); for (int i = 0; i <stack; i ++) {indent.append ( ""); } indent.toString ()을 반환합니다. }
코드 크랩

예 [user1912935]는 @codeskraps가 쓴, 간단한 충분히 :)해야한다
milosmns

루프 내에서 StringBuilder와 연결 : 나쁜 습관.
james.garriss

@ james.garriss 그러나 새로운 줄로 나누는 것은 매우 쉽습니다. 이것은 DOM 트리가없는 간단한 접근 방식을 보여줍니다.
milosmns

5

위의 모든 솔루션이 저에게 효과가 없었습니다. http://myshittycode.com/2014/02/10/java-properly-indenting-xml-string/

실마리는 XPath로 공백을 제거하는 것입니다

    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 } indent-amount'속성을 사용하면 특정 변환기 구현에 연결됩니다.
vallismortis 2016 년

1
모든 솔루션 에서이 솔루션이 가장 효과적이었습니다. XML에 공백과 줄이 이미 있었고 프로젝트에 더 많은 종속성을 추가하고 싶지 않았습니다. XML을 파싱하지 않아도 좋기를 바랍니다.
Fabio

5

아래 코드는 완벽하게 작동합니다.

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

나는 그것들을 모두 섞어서 하나의 작은 프로그램을 작성합니다. xml 파일에서 읽고 인쇄합니다. xzy 대신 파일 경로를 지정하십시오.

    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

우리에게 적합한 또 다른 솔루션

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 사용 : 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 Easleymilosmns 는 경량의 고성능 프리티 프린터 라이브러리 인 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
}

때로는 모의 SOAP 서비스를 파일에서 직접 실행할 때와 같이 이미 인쇄 된 XML을 처리하는 프리티 프린터가있는 것이 좋습니다.

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

일부 사람들이 언급했듯이, 예쁜 인쇄는 XML을 사람이 읽을 수있는 형태로 표현하는 방법 일뿐입니다. 공백은 XML 데이터에 속하지 않습니다.

이 라이브러리는 로깅 목적으로 예쁘게 인쇄하기위한 것이며 CDATA 및 텍스트 노드에서 XML을 필터링 (하위 트리 제거 / 익명화)하고 예쁘게 인쇄하는 기능도 포함합니다.


2

나는 같은 문제가 있었고 JTidy ( http://jtidy.sourceforge.net/index.html)로 큰 성공을 거두었습니다. )에서

예:

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

Underscore-java 에는 정적 메소드가 U.formatXml(string)있습니다. 나는 프로젝트의 관리자입니다. 라이브 예

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

산출:

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

대단해!
senyor

1

xmlstarlet ( http://xmlstar.sourceforge.net/ ) 이라는 매우 훌륭한 명령 행 xml 유틸리티 가있어 많은 사람들이 사용하는 많은 작업을 수행 할 수 있습니다.

Runtime.exec를 사용 하여이 프로그램을 프로그래밍 방식으로 실행 한 다음 형식이 지정된 출력 파일을 읽을 수 있습니다. 몇 줄의 Java 코드가 제공 할 수있는 것보다 더 많은 옵션과 더 나은 오류보고 기능이 있습니다.

xmlstarlet 다운로드 : http://sourceforge.net/project/showfiles.php?group_id=66612&package_id=64589


1

Java 1.6.0_32에서 XML 문자열 을 꽤 인쇄하는 일반적인 방법 (null 또는 identity xslt가있는 Transformer 사용)은 태그가 공백이 아닌 분리 된 것과는 달리 원하는대로 작동하지 않는다는 것을 알았습니다. 본문. 나는 사용하여 시도 <xsl:strip-space elements="*"/>아무 소용이 내 템플릿. 내가 찾은 가장 간단한 해결책은 SAXSource 및 XML 필터를 사용하여 원하는 방식으로 공간을 제거하는 것이 었습니다. 내 솔루션은 로깅을위한 것이기 때문에 불완전한 XML 조각으로 작동하도록 확장했습니다. DOMSource를 사용하면 정상적인 방법이 잘 작동하지만 불완전 성과 메모리 오버 헤드로 인해 이것을 사용하고 싶지 않습니다.

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 이상에서 찾은 솔루션은 코드가 이미 포맷 된 경우 코드를 다시 포맷하지 않습니다. 나를 위해 일한 (그리고 이미 포맷 된 코드를 다시 포맷 한) 것은 다음과 같습니다.

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

전체 문자열 xml 비교를 위해 단위 테스트에 사용하는 것이 좋습니다.

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이 100 % 유효 할 필요가 없습니다. 예를 들어 REST / SOAP 로깅의 경우 (다른 사람이 무엇을 보내는 지 전혀 모른다 ;-)

온라인에서 찾은 코드를 발견하고 진행했습니다.

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

출력은 다음과 같습니다.

<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

나는을 사용하여 하나의 답변 을 보았 Scala으므로 Groovy누군가가 그것을 흥미롭게 생각하는 경우를 대비 하여 또 다른 답변 이 있습니다. 기본 들여 쓰기는 2 단계이며 XmlNodePrinter생성자에도 다른 값을 전달할 수 있습니다.

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가 클래스 경로에있는 경우 Java에서 사용

  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

들여 쓰기가 필요하지 않지만 몇 줄의 줄 바꿈이 필요한 경우 간단히 정규 표현식으로 충분할 수 있습니다 ...

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

들여 쓰기가 누락되어 결과가 아닌 코드가 좋습니다.


들여 쓰기가있는 솔루션에 대해서는 다른 답변을 참조하십시오.


1
흠 ... 그냥 큰 소리로 생각하면 누가 그런 해결책이 필요할까요? 내가 볼 수있는 유일한 부분은 일부 웹 서비스에서 얻은 데이터이며 해당 데이터와 그 유효성을 테스트하기 위해 개발자 또는 테스터에게는 쉬운 데이터가 필요할 수 있습니다. 그렇지 않으면 안 좋은 옵션 ...
Sudhakar Chavali

1
@SudhakarChavali 저는 개발자입니다. 더러운 println () 및 log.debug () 해킹의 경우 필요할 수 있습니다. 즉, 프로그램을 단계별로 디버깅하는 대신 제한된 서버 환경 (쉘 액세스 대신 웹 관리자 인터페이스 사용) 내에서만 로그 파일을 사용할 수 있습니다.
comonad
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.