之前实现的一个版本:http://www.cnblogs.com/lyhtbc/p/jaxp-pretty-format-validate-validation-stax-stax2.html
这个版本中存一个问题:如果某一个节点的值是空的话,会换行输出结束标签,如:
<a>
</a>
某些场景下会要求节点内必须要有值,否则就应该输出为 <a/>(例如XBRL instance的schemaLink节点)。
新代码如下:
XMLPrettyFormatter:
import javax.xml.stream.XMLStreamException; /**
* XML pretty formatter.
*/
public interface XMLPrettyFormatter { enum NodeType {
ELEMENT, VALUE, NULL
} String DEFAULT_INDENTION = "\t"; void writeStartElementIndention() throws XMLStreamException; /**
* @param blankValue
* True if the value is null of blank character.
*/
void writeValueIndention(boolean blankValue) throws XMLStreamException; void writeEndElementIndention() throws XMLStreamException; }
DefaultPrettyFormatter:
import java.util.LinkedList; import javax.xml.stream.XMLStreamException; import org.codehaus.stax2.XMLStreamWriter2; /**
* Default XML pretty formatter.
* <ol>
* <li>Default intention is tab character "\t".</li>
* <li>The value display in the same line with which element it belongs to.</li>
* <li>If value is blank, don't use separate end tag.</li>
* </ol>
*/
public class DefaultPrettyFormatter implements XMLPrettyFormatter { private String indent = DEFAULT_INDENTION; private LinkedList<NodeType> stack = new LinkedList<XMLPrettyFormatter.NodeType>(); private XMLStreamWriter2 writer; public DefaultPrettyFormatter(XMLStreamWriter2 writer) {
this.writer = writer;
} public DefaultPrettyFormatter(XMLStreamWriter2 writer, String indent) {
this.writer = writer;
this.indent = indent;
} @Override
public void writeStartElementIndention() throws XMLStreamException {
NodeType lastNode = stack.peek();
if (lastNode != null && lastNode == NodeType.NULL) {
stack.pop();
} writeLineBreaker();
for (int i = 0; i < stack.size(); ++i) {
writeIndention();
} stack.push(NodeType.ELEMENT); // default value node
stack.push(NodeType.NULL);
} @Override
public void writeValueIndention(boolean blankValue) throws XMLStreamException {
if (!blankValue) {
// if value is not blank, pop default blank node first.
stack.pop();
stack.push(NodeType.VALUE);
}
} @Override
public void writeEndElementIndention() throws XMLStreamException {
NodeType lastNode = stack.pop();
if (lastNode == NodeType.ELEMENT) {
writeLineBreaker();
for (int i = 0; i < stack.size(); ++i) {
writeIndention();
}
} else {
// pop start element
stack.pop();
}
} private void writeLineBreaker() throws XMLStreamException {
writer.writeCharacters("\n");
} private void writeIndention() throws XMLStreamException {
writer.writeCharacters(indent.toCharArray(), 0, indent.length());
} }