package org.docbag.xml;
import java.io.CharArrayWriter;
import java.util.ArrayDeque;
import java.util.Deque;
import org.docbag.template.transformer.TransformerException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;
import org.xml.sax.Attributes;
/**
* Helper class.
*
* @author Jakub Torbicki
*/
public class XMLContent {
private static final Logger Log = LoggerFactory.getLogger(XMLContent.class);
private final CharArrayWriter writer = new CharArrayWriter();
private NameSpaceStack namespaces = new NameSpaceStack();
private boolean complete = false;
public boolean isComplete() {
return complete;
}
public void complete() {
complete = true;
// null namespaces to help GC, but don't null writer since we need it in the getContent() operation
namespaces = null;
complete = true;
}
public String getContent() {
return writer.toString();
}
public void enterNamespace(String prefix, String uri) {
if (namespaces.needNewContext) {
namespaces.pushContext();
namespaces.needNewContext = false;
}
namespaces.getCurrentContext().addNameSpace(prefix, uri);
}
public void leaveAllNamespaces() {
namespaces.popContext();
}
public void append(String str) {
checkIfNotCompleted();
if (str != null && str.length() > 0) {
writer.write(str.toCharArray(), 0, str.length());
} else {
if (Log.isDebugEnabled()) {
Log.debug("There was a try to add empty string to XMLContent");
}
}
}
public void startElement(String uri, String localName, String qName, Attributes attributes) {
if (namespaces.needNewContext) {
namespaces.pushContext();
}
namespaces.needNewContext = true;
StringBuilder b = new StringBuilder();
b.append("<");
b.append(qName);
NameSpaceStack.NameSpace[] nameSpaces = namespaces.getCurrentContext().listNameSpaces();
if (nameSpaces.length > 0) {
for (NameSpaceStack.NameSpace nameSpace : nameSpaces) {
if (StringUtils.hasText(nameSpace.getPrefix())) {
b.append(" xmlns:").append(nameSpace.getPrefix()).append("=\"").append(nameSpace.getUri()).append("\"");
} else {
b.append(" xmlns=\"").append(nameSpace.getUri()).append("\"");
}
}
}
if (attributes != null) {
int length = attributes.getLength();
for (int i = 0; i < length; i++) {
String attr = " " + attributes.getQName(i) + "=\"" + attributes.getValue(i) + "\"";
b.append(attr);
}
}
b.append(">");
append(b.toString());
}
public void endElement(String name) {
append("</" + name + ">");
}
private void checkIfNotCompleted() {
if (complete) {
throw new TransformerException("XMLContent already complete! Can't add new content.");
}
}
private static class NameSpaceStack {
private final Deque<NameSpaceContext> queue = new ArrayDeque<NameSpaceContext>();
private boolean needNewContext = true;
public NameSpaceStack() {
}
public void pushContext() {
queue.push(new NameSpaceContext());
}
public void popContext() {
queue.pop();
}
public NameSpaceContext getCurrentContext() {
return queue.peek();
}
private static class NameSpaceContext {
private final Deque<NameSpace> queue = new ArrayDeque<NameSpace>();
public void addNameSpace(String prefix, String uri) {
queue.push(new NameSpace(prefix, uri));
}
public NameSpace[] listNameSpaces() {
return queue.toArray(new NameSpace[queue.size()]);
}
}
private static class NameSpace {
private final String prefix;
private final String uri;
public NameSpace(String prefix, String uri) {
this.prefix = prefix;
this.uri = uri;
}
public String getPrefix() {
return prefix;
}
public String getUri() {
return uri;
}
}
}
}