import java.util.*; import java.io.*; public class XMLStream { Writer w; Stack tags = new Stack(); XMLStreamElement currentElement; boolean wroteData; boolean startTagClosed; boolean tight = true; String spacer = " "; Hashtable atts = new Hashtable(); public XMLStream() { this(new StringWriter()); } public XMLStream(java.io.Writer writer) { this.w = writer; } public String currentTagName() { if (currentElement == null) return null; return currentElement.name; } public void setTight(boolean b) { tight = b; } public void setSpacer(String s) { spacer = s; } private void indent() throws IOException { if (!tight) { w.write("\n"); int count = tags.size(); for (int i = 1; i < count; i++) { w.write(spacer); } } } public XMLStream tag(String tag) throws IOException { return tag(tag, null, null); } public XMLStream tag(String tag, String name, String value) throws IOException { startTag(tag); if (name != null) addAttribute(name, value); closeTag(); return this; } public XMLStream tag(String tag, String [] atts) throws IOException { startTag(tag); if (atts != null) aa(atts); closeTag(); return this; } public XMLStream startTag(String tag) throws IOException { if (currentElement != null) currentElement.nested = true; currentElement = new XMLStreamElement(tag); tags.push(currentElement); if (tags.size() > 1 && !startTagClosed) { w.write(">"); } indent(); w.write("<"); w.write(tag); startTagClosed = false; wroteData = false; return this; } public XMLStream aa(String [] atts) throws IOException { if (atts.length % 2 != 0) throw new RuntimeException("an uneven number of args was passed to aa!"); for (int i = 0; i < atts.length; i += 2) { aa(atts[i], atts[i+1]); } return this; } public XMLStream aa(String name, String value) throws IOException { return addAttribute(name, value); } public XMLStream addAttribute(String name, String value) throws IOException { w.write(" "); w.write(name); w.write("=\""); int len = value.length(); for (int i = 0; i < len; i++) { if (value.charAt(i) == '"') { w.write("&#" + ((int)'"') + ";"); } else { write(value.charAt(i)); } } w.write("\""); return this; } public XMLStream addAttributes(Map m) throws IOException { Iterator it = m.keySet().iterator(); while (it.hasNext()) { String name = (String)it.next(); addAttribute(name, (String)m.get(name)); } return this; } public XMLStream closeTag() throws IOException { XMLStreamElement tag = (XMLStreamElement)tags.pop(); if (wroteData) { w.write(""); } else { if (tag.nested) { tags.push(""); indent(); tags.pop(); w.write(""); } else { w.write(" />"); } } wroteData = false; startTagClosed = true; return this; } public XMLStream write(String data) throws IOException { return write(data, true); } public XMLStream write(String data, boolean escape) throws IOException { wroteData = true; if (!startTagClosed) { w.write(">"); startTagClosed = true; } if (escape) { int len = data.length(); for (int i = 0; i < len; i++) { write(data.charAt(i)); } } else { w.write(data); } return this; } private void write(char c) throws IOException { if ((int)c == 8226) w.write("•"); else if ((int)c > 127 && (int)c<256) w.write("&#" + ((int)c) + ";"); else if ('&' == c) w.write("&"); else if ('>' == c) w.write(">"); else if ('<' == c) w.write("<"); else w.write(new String(new char [] {c})); } public String toString() { if (w instanceof StringWriter) { return w.toString(); } return this.toString(); } public static void main(String [] args) { XMLStream xs = new XMLStream(); xs.setTight(false); try { xs.startTag("pdfdoc"); xs.startTag("image"); xs.addAttribute("src", "http://gusmueller.com/images/bob.gif"); xs.addAttribute("width", "100"); xs.addAttribute("height", "50"); xs.closeTag(); Hashtable h = new Hashtable(); h.put("leading", "5"); h.put("height", "40"); h.put("copyFit", "true"); h.put("width", "250"); xs.startTag("text"); xs.addAttributes(h); xs.write("This is the text & stuff < lalala$& !!!!!!\u2022"); xs.closeTag(); xs.startTag("table"); xs.startTag("tr"); xs.tag("td"); xs.startTag("td"); xs.write("hi from td"); xs.closeTag(); xs.closeTag(); xs.startTag("tr"); xs.tag("td"); xs.closeTag(); xs.closeTag(); xs.tag("font", "name", "Helvetica"); xs.closeTag(); System.out.println(xs.toString()); } catch (Exception e) { e.printStackTrace(System.out); } } } class XMLStreamElement { boolean nested; String name; XMLStreamElement(String name) { this.name = name; } }