1 package dolda.jsvc.next;
6 import dolda.jsvc.util.Misc;
8 public class XmlWriter {
9 private Map<String, String> nsnames = new HashMap<String, String>();
10 public final Document doc;
11 private int nsser = 1;
13 public XmlWriter(Document doc) {
17 public void setnsname(String uri, String name) {
18 nsnames.put(uri, name);
21 private String nsname(String uri) {
23 if(nsnames.containsKey(uri))
24 return(nsnames.get(uri));
26 ret = "n" + (nsser++);
27 } while(nsnames.containsValue(ret));
28 nsnames.put(uri, ret);
32 protected void findallnsnames() {
35 String ns = n.getNamespaceURI();
38 if(n.getFirstChild() != null) {
39 n = n.getFirstChild();
40 } else if(n.getNextSibling() != null) {
41 n = n.getNextSibling();
43 for(n = n.getParentNode(); n != null; n = n.getParentNode()) {
44 if(n.getNextSibling() != null) {
45 n = n.getNextSibling();
55 protected boolean prebreak(ColumnWriter out, Element el) {
59 protected int indent(ColumnWriter out, Element el) {
63 protected boolean postbreak(ColumnWriter out, Element el) {
67 protected boolean asempty(ColumnWriter out, Element el) {
71 protected void attribute(ColumnWriter out, String nm, String val, int indent) throws IOException {
73 if((val.indexOf("\"") >= 0) && (val.indexOf('\'') < 0))
75 out.write(" " + nm + "=" + qt);
76 for(int i = 0; i < val.length(); i++) {
77 char c = val.charAt(i);
85 out.write((c == '\'')?"'":""");
92 protected void attribute(ColumnWriter out, Attr attr, int indent) throws IOException {
93 String ns = attr.getNamespaceURI();
95 attribute(out, attr.getName(), attr.getValue(), indent);
97 attribute(out, nsname(ns) + ":" + attr.getName(), attr.getValue(), indent);
100 protected void element(ColumnWriter out, Element el, int indent) throws IOException {
101 if(prebreak(out, el))
104 String tagname = el.getTagName();
105 String ns = nsname(el.getNamespaceURI());
107 tagname = ns + ":" + tagname;
108 out.write("<" + tagname);
109 NamedNodeMap attrs = el.getAttributes();
110 int acol = out.col + 1;
112 for(int i = 0; i < attrs.getLength(); i++) {
113 Attr attr = (Attr)attrs.item(i);
114 attribute(out, attr, acol);
117 if(el == doc.getDocumentElement()) {
118 for(Map.Entry<String, String> nd : nsnames.entrySet()) {
119 String nm = nd.getValue();
121 attribute(out, "xmlns", nd.getKey(), acol);
123 attribute(out, "xmlns:" + nm, nd.getKey(), acol);
127 if((el.getFirstChild() == null) && asempty(out, el)) {
131 int inner = indent(out, el);
133 out.indent(indent + inner);
136 for(Node ch = el.getFirstChild(); ch != null; ch = ch.getNextSibling())
137 node(out, ch, (inner >= 0)?(indent + inner):indent);
141 out.write("</" + tagname + ">");
144 if(postbreak(out, el))
148 protected void text(ColumnWriter out, String s, int indent) throws IOException {
149 out.write(Misc.htmlq(s));
152 protected void text(ColumnWriter out, Text txt, int indent) throws IOException {
153 String s = txt.getData();
154 text(out, s, indent);
157 protected void comment(ColumnWriter out, Comment c, int indent) throws IOException {
159 String s = c.getData();
160 text(out, s, indent);
164 protected void node(ColumnWriter out, Node n, int indent) throws IOException {
165 if(n instanceof Element) {
166 Element el = (Element)n;
167 element(out, el, indent);
168 } else if(n instanceof Text) {
170 text(out, txt, indent);
171 } else if(n instanceof Comment) {
172 Comment c = (Comment)n;
173 comment(out, c, indent);
175 throw(new RuntimeException(String.format("Unknown DOM node encountered (%s)", n.getClass())));
179 protected void doctype(ColumnWriter out, DocumentType dt) throws IOException {
180 out.write(String.format("<!DOCTYPE %s PUBLIC \"%s\" \"%s\">\n", dt.getName(), dt.getPublicId(), dt.getSystemId()));
183 public void write(Writer out) throws IOException {
185 ColumnWriter col = new ColumnWriter(out);
186 DocumentType t = doc.getDoctype();
189 node(col, doc.getDocumentElement(), 0);
192 public void write(OutputStream out) throws IOException {
193 /* The OutputStreamWriter may need to be flushed to clear any
194 * internal buffers it may have, but it would be a pity to
195 * force-flush the underlying stream just because of that. */
196 class FlushGuard extends FilterOutputStream {
197 FlushGuard(OutputStream out) {
201 public void flush() {}
203 Writer w = new OutputStreamWriter(new FlushGuard(out), Misc.utf8);
204 w.write("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n");