之前实现的一个版本:
这个版本中存一个问题:如果某一个节点的值是空的话,会换行输出结束标签,如:
<a>
</a>
某些场景下会要求节点内必须要有值,否则就应该输出为 <a/>(例如XBRL instance的schemaLink节点)。
新代码如下:
XMLPrettyFormatter:
1 import javax.xml.stream.XMLStreamException; 2 3 /** 4 * XML pretty formatter. 5 */ 6 public interface XMLPrettyFormatter { 7 8 enum NodeType { 9 ELEMENT, VALUE, NULL10 }11 12 String DEFAULT_INDENTION = "\t";13 14 void writeStartElementIndention() throws XMLStreamException;15 16 /**17 * @param blankValue18 * True if the value is null of blank character.19 */20 void writeValueIndention(boolean blankValue) throws XMLStreamException;21 22 void writeEndElementIndention() throws XMLStreamException;23 24 }
DefaultPrettyFormatter:
1 import java.util.LinkedList; 2 3 import javax.xml.stream.XMLStreamException; 4 5 import org.codehaus.stax2.XMLStreamWriter2; 6 7 /** 8 * Default XML pretty formatter. 9 *10 *
14 */15 public class DefaultPrettyFormatter implements XMLPrettyFormatter {16 17 private String indent = DEFAULT_INDENTION;18 19 private LinkedList- Default intention is tab character "\t".
11 *- The value display in the same line with which element it belongs to.
12 *- If value is blank, don't use separate end tag.
13 *stack = new LinkedList ();20 21 private XMLStreamWriter2 writer;22 23 public DefaultPrettyFormatter(XMLStreamWriter2 writer) {24 this.writer = writer;25 }26 27 public DefaultPrettyFormatter(XMLStreamWriter2 writer, String indent) {28 this.writer = writer;29 this.indent = indent;30 }31 32 @Override33 public void writeStartElementIndention() throws XMLStreamException {34 NodeType lastNode = stack.peek();35 if (lastNode != null && lastNode == NodeType.NULL) {36 stack.pop();37 }38 39 writeLineBreaker();40 for (int i = 0; i < stack.size(); ++i) {41 writeIndention();42 }43 44 stack.push(NodeType.ELEMENT);45 46 // default value node47 stack.push(NodeType.NULL);48 }49 50 @Override51 public void writeValueIndention(boolean blankValue) throws XMLStreamException {52 if (!blankValue) {53 // if value is not blank, pop default blank node first.54 stack.pop();55 stack.push(NodeType.VALUE);56 }57 }58 59 @Override60 public void writeEndElementIndention() throws XMLStreamException {61 NodeType lastNode = stack.pop();62 if (lastNode == NodeType.ELEMENT) {63 writeLineBreaker();64 for (int i = 0; i < stack.size(); ++i) {65 writeIndention();66 }67 } else {68 // pop start element69 stack.pop();70 }71 }72 73 private void writeLineBreaker() throws XMLStreamException {74 writer.writeCharacters("\n");75 }76 77 private void writeIndention() throws XMLStreamException {78 writer.writeCharacters(indent.toCharArray(), 0, indent.length());79 }80 81 }