민서네집

how to pretty print xml from Java 본문

Java

how to pretty print xml from Java

브라이언7 2013. 5. 25. 12:07

자바에서 xml 을 예쁘게 indent 해서 변환하려면...?


[출처] http://stackoverflow.com/questions/139076/how-to-pretty-print-xml-from-java


이미 검증된 xml 파일이라면 굳이 dom 으로 변환하지 않고, indent 만 넣어서 변환해주는 소스가 있다.


메모리도 아끼고, 속도도 빠를듯 하다.


여기 있는 코드를 가지고 돌려봤더니 line wrap 이 이상하게 동작했다.


나는 line wrap 기능을 쓰지 않고, synchronized 지시어를 빼도 되도록 멤버변수를 사용하지 않도록 코드를 수정했다.

또, 위 웹사이트에 있는 원래 코드는 한줄로 쭉 이어진 xml 에 대해서만 정렬이 되고, xml 노드마다 줄바꿈 문자가 들어간 경우라던지 어느 정도 indent 가 된 xml 에 대해서는 작동하지 않는다. 나는 이런 경우에 대해서도 똑같이 정렬이 되도록 코드를 수정했다.


수정한 코드는 다음과 같다.


package me.bryan7.util;

/**
 * XML utils, including formatting.
 * 

* [출처] <a href='http://stackoverflow.com/questions/139076/how-to-pretty-print-xml-from-java'>http://stackoverflow.com/questions/139076/how-to-pretty-print-xml-from-java</a> */ public class XmlUtils { private static XmlFormatter formatter = new XmlFormatter(); private static final int DEFAULT_INDENT_NUM_CHARS = 4; public static String formatXml(String s) { if( s == null ) return s; return formatter.format(s, DEFAULT_INDENT_NUM_CHARS, 0); } public static String formatXml(String s, int initialIndent) { if( s == null ) return s; return formatter.format(s, DEFAULT_INDENT_NUM_CHARS, initialIndent); } private static class XmlFormatter {

// XML 노드의 값이 여기에 지정된 글자수가 넘어가면 노드와 같은 줄이 아니라 다음 줄에 표시된다. private static final int SINGLE_LINE_CHAR_NUMS = 500; // [2013-05-29] hskang - synchronized 를 걸 필요가 없으므로 성능 향상을 위해서 뺐음. // 이 메서드 안에서는 멤버변수를 사용하지 않음. 파라미터는 Stack에 저장되므로 멀티 쓰레드라 하더라도 공유하지 않음. // public synchronized String format(String s, int initialIndent) public String format(String s, int indentNumChars, int initialIndent) { boolean singleLine = false; 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; } int nextStartElementPos = s.indexOf('<', i); if (nextStartElementPos > i + 1) { String textBetweenElements = s.substring(i + 1, nextStartElementPos); if( textBetweenElements.trim().length() == 0 ) { textBetweenElements = "\n"; sb.append(textBetweenElements); } else { if( textBetweenElements.length() > SINGLE_LINE_CHAR_NUMS ) { sb.append("\n" + buildWhitespace(indent) + textBetweenElements + "\n"); } else { sb.append(textBetweenElements); singleLine = true; } } i = nextStartElementPos - 1; } else if( nextStartElementPos == i + 1 ) { sb.append("\n"); } } } return sb.toString(); } } private static StringBuilder buildWhitespace(int numChars) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < numChars; i++) sb.append(" "); return sb; } public static void main(String[] args) { StringBuilder sample1 = new StringBuilder("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"); sample1.append("<SyncML xmlns=\"SYNCML:SYNCML1.2\">\n"); sample1.append(" <SyncHdr>\n"); sample1.append(" <VerDTD>12345678901234567890123456789012345678901</VerDTD>\n"); sample1.append(" </SyncHdr>\n"); sample1.append("<Final/>\n"); sample1.append("</SyncML>\n"); StringBuilder sample2 = new StringBuilder("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"); sample2.append("<SyncML xmlns=\"SYNCML:SYNCML1.2\">"); sample2.append("<SyncHdr>"); sample2.append("<VerDTD>1.2</VerDTD>"); sample2.append("</SyncHdr>"); sample2.append("<Final/>"); sample2.append("</SyncML>"); StringBuilder sample3 = new StringBuilder("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"); sample3.append("<SyncML xmlns=\"SYNCML:SYNCML1.2\">\n"); sample3.append("<SyncHdr>\n"); sample3.append("<VerDTD>1.2</VerDTD>\n"); sample3.append("</SyncHdr>\n"); sample3.append("<Final/>\n"); sample3.append("</SyncML>\n"); String formatXml = XmlUtils.formatXml(sample1.toString()); System.out.println(formatXml); System.out.println("#########################"); } }


Comments