package com.yoursway.utils;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.List;
public class XmlWriter {
static public String escapeXml(String str) {
str = replaceString(str, "&", "&");
str = replaceString(str, "<", "<");
str = replaceString(str, ">", ">");
str = replaceString(str, "\"", """);
str = replaceString(str, "'", "'");
return str;
}
public static final String UTF8_ENCODING = "UTF-8";
private Writer writer;
private List<String> openElements = new ArrayList<String>();
private StringBuilder attrs = new StringBuilder();
private boolean currentElementIsEmpty;
private boolean rightAngleBracketIsWritten = true;
private boolean insideProcessingInstruction = false;
private String encoding;
public XmlWriter(Writer writer) {
if (writer == null)
throw new NullPointerException("writer is null");
this.writer = writer;
}
public XmlWriter(OutputStream stream) throws UnsupportedEncodingException {
this(stream, UTF8_ENCODING);
}
public XmlWriter(OutputStream stream, String encoding)
throws UnsupportedEncodingException {
this(new OutputStreamWriter(stream, encoding));
this.encoding = encoding;
}
public XmlWriter setEncoding(String encoding) {
this.encoding = encoding;
return this;
}
public void finish() throws IOException {
if (!openElements.isEmpty()) {
throw new IllegalStateException("Tags are not all closed. "
+ "Possibly, " + pop(openElements) + " is unclosed. ");
}
writer.flush();
}
public XmlWriter end() throws IOException {
if (insideProcessingInstruction) {
writeAttributes();
writer.write("?>\r\n");
insideProcessingInstruction = false;
} else {
if (openElements.isEmpty())
throw new IllegalStateException("Called end() too many times.");
String name = pop(openElements);
if (currentElementIsEmpty) {
writeAttributes();
writer.write("/>");
rightAngleBracketIsWritten = true;
} else {
writer.write("</");
writer.write(name);
writer.write(">");
}
currentElementIsEmpty = false;
}
return this;
}
public XmlWriter start(String name, String attr1, String value1)
throws IOException {
return start(name).attr(attr1, value1);
}
public XmlWriter start(String name, String attr1, String value1,
String attr2, String value2) throws IOException {
return start(name).attr(attr1, value1).attr(attr2, value2);
}
public XmlWriter start(String name, String attr1, String value1,
String attr2, String value2, String attr3, String value3)
throws IOException {
return start(name).attr(attr1, value1).attr(attr2, value2).attr(attr3,
value3);
}
public XmlWriter start(String name, String attr1, String value1,
String attr2, String value2, String attr3, String value3,
String attr4, String value4) throws IOException {
return start(name).attr(attr1, value1).attr(attr2, value2).attr(attr3,
value3).attr(attr4, value4);
}
public XmlWriter start(String name) throws IOException {
if (name == null)
throw new NullPointerException("name is null");
closeOpeningTag();
rightAngleBracketIsWritten = false;
writer.write("<");
writer.write(name);
openElements.add(name);
currentElementIsEmpty = true;
return this;
}
public XmlWriter xmlHeader(String attr1, String value1) throws IOException {
return startXmlHeader().attr(attr1, value1).end();
}
public XmlWriter xmlHeader(String attr1, String value1, String attr2,
String value2) throws IOException {
return startXmlHeader().attr(attr1, value1).attr(attr2, value2).end();
}
public XmlWriter xmlHeader(String attr1, String name1, String attr2,
String value2, String attr3, String value3) throws IOException {
return startXmlHeader().attr(attr1, name1).attr(attr2, value2).attr(
attr3, value3).end();
}
public XmlWriter startXmlHeader() throws IOException {
startProcessingInstruction("xml").attr("version", "1.0");
if (encoding != null)
attr("encoding", encoding);
return this;
}
public XmlWriter processingInstruction(String name, String attr1,
String value1) throws IOException {
return startProcessingInstruction(name).attr(attr1, value1).end();
}
public XmlWriter processingInstruction(String name, String attr1,
String value1, String attr2, String value2) throws IOException {
return startProcessingInstruction(name).attr(attr1, value1).attr(attr2,
value2).end();
}
public XmlWriter processingInstruction(String name, String attr1,
String value1, String attr2, String value2, String attr3,
String value3) throws IOException {
return startProcessingInstruction(name).attr(attr1, value1).attr(attr2,
value2).attr(attr3, value3).end();
}
public XmlWriter processingInstruction(String name) throws IOException {
return startProcessingInstruction(name).end();
}
public XmlWriter startProcessingInstruction(String name) throws IOException {
if (name == null)
throw new NullPointerException("name is null");
closeOpeningTag();
writer.write("<?");
writer.write(name);
insideProcessingInstruction = true;
return this;
}
public XmlWriter xmlns(String url) throws IOException {
return attr("xmlns", url);
}
public XmlWriter xmlns(String shortcut, String url) throws IOException {
if (shortcut == null || shortcut.length() == 0)
return attr("xmlns", url);
else
return attr("xmlns:" + shortcut, url);
}
public XmlWriter tag(String name, String content) throws IOException {
return start(name).text(content).end();
}
public XmlWriter tag(String name, String attr1, String value1,
String content) throws IOException {
return start(name).attr(attr1, value1).text(content).end();
}
public XmlWriter tag(String name, String attr1, String value1,
String attr2, String value2, String content) throws IOException {
return start(name).attr(attr1, value1).attr(attr2, value2)
.text(content).end();
}
public XmlWriter tag(String name, String attr1, String value1,
String attr2, String value2, String attr3, String value3,
String content) throws IOException {
return start(name).attr(attr1, value1).attr(attr2, value2).attr(attr3,
value3).text(content).end();
}
public XmlWriter tag(String name) throws IOException {
return start(name).end();
}
public XmlWriter tag(String name, String attr1, String value1)
throws IOException {
return start(name).attr(attr1, value1).end();
}
public XmlWriter tag(String name, String attr1, String value1,
String attr2, String value2) throws IOException {
return start(name).attr(attr1, value1).attr(attr2, value2).end();
}
public XmlWriter tag(String name, String attr1, String value1,
String attr2, String value2, String attr3, String value3)
throws IOException {
return start(name).attr(attr1, value1).attr(attr2, value2).attr(attr3,
value3).end();
}
public XmlWriter tag(String name, String attr1, String value1,
String attr2, String value2, String attr3, String value3,
String attr4, String value4) throws IOException {
return start(name).attr(attr1, value1).attr(attr2, value2).attr(attr3,
value3).attr(attr4, value4).end();
}
public XmlWriter attr(String attr, String value) throws IOException {
if (attr == null)
throw new NullPointerException("attr is null");
if (value == null)
throw new NullPointerException("value is null");
attrs.append(" ");
attrs.append(attr);
attrs.append("=\"");
attrs.append(escapeXml(value));
attrs.append("\"");
return this;
}
public XmlWriter text(String text) throws IOException {
if (text == null)
throw new NullPointerException("text is null");
closeOpeningTag();
currentElementIsEmpty = false;
writer.write(escapeXml(text));
return this;
}
private void closeOpeningTag() throws IOException {
if (insideProcessingInstruction)
end();
if (!rightAngleBracketIsWritten) {
writeAttributes();
rightAngleBracketIsWritten = true;
writer.write(">");
}
}
private void writeAttributes() throws IOException {
if (attrs.length() > 0) {
writer.write(attrs.toString());
attrs.setLength(0);
currentElementIsEmpty = false;
}
}
private static String replaceString(String text, String repl, String with) {
return replaceString(text, repl, with, -1);
}
private static String replaceString(String text, String repl, String with,
int max) {
if (text == null) {
return null;
}
StringBuilder buffer = new StringBuilder(text.length());
int start = 0;
int end = 0;
while ((end = text.indexOf(repl, start)) != -1) {
buffer.append(text.substring(start, end)).append(with);
start = end + repl.length();
if (--max == 0) {
break;
}
}
buffer.append(text.substring(start));
return buffer.toString();
}
private static <T> T pop(List<T> list) {
return list.remove(list.size() - 1);
}
}