JAXP使用Stax API时格式化输出XML 2
之前实现的一个版本:http://www.cnblogs.com/lyhtbc/p/jaxp-pretty-format-validate-validation-stax-stax2.html
这个版本中存一个问题:如果某一个节点的值是空的话,会换行输出结束标签,如:
<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, NULL 10 } 11 12 String DEFAULT_INDENTION = "\t"; 13 14 void writeStartElementIndention() throws XMLStreamException; 15 16 /** 17 * @param blankValue 18 * 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 * <ol> 10 * <li>Default intention is tab character "\t".</li> 11 * <li>The value display in the same line with which element it belongs to.</li> 12 * <li>If value is blank, don't use separate end tag.</li> 13 * </ol> 14 */ 15 public class DefaultPrettyFormatter implements XMLPrettyFormatter { 16 17 private String indent = DEFAULT_INDENTION; 18 19 private LinkedList<NodeType> stack = new LinkedList<XMLPrettyFormatter.NodeType>(); 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 @Override 33 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 node 47 stack.push(NodeType.NULL); 48 } 49 50 @Override 51 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 @Override 60 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 element 69 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 }