package org.kxml.io; import java.io.*; import java.util.*; import org.kxml.*; /** An abstract XmlWriter including namespace handling. */ public abstract class AbstractXmlWriter extends Writer { protected State current = new State (null, new PrefixMap (), //null, null, null); protected class State { public State prev; public PrefixMap prefixMap; // String namespace; // String name; public String tag; // for auto-endtag writing public State (State prev, PrefixMap prefixMap, //String namespace, String name, String tag) { this.prev = prev; this.prefixMap = prefixMap; // this.namespace = namespace; // this.name = name; this.tag = tag; } } /** writes an attribute. Only allowed immediately after startTag or attribute. */ public abstract void attribute (String name, String value) throws IOException; /** writes an attribute with the given namespace. Only allowed immediately after startTag or another attribute call. */ public void attribute (String namespace, String name, String value) throws IOException { if (namespace == null || "".equals (namespace)) attribute (name, value); else { String prefix = current.prefixMap.getPrefix (namespace); if (prefix == null || prefix.equals ("")) { int cnt = 0; do { prefix = "p"+(cnt++); } while (current.prefixMap.getNamespace (prefix) != null); current.prefixMap = new PrefixMap (current.prefixMap, prefix, namespace); attribute ("xmlns:"+prefix, namespace); } attribute (prefix + ":" + name, value); } } public PrefixMap getPrefixMap () { return current.prefixMap; } /** writes a start tag with the given name, using the given prefix map. This method cares about the namespace prefixes and calls startTag (PrefixMap prefixMap, String tag) for concrete writing. */ public void startTag (PrefixMap prefixMap, String namespace, String name) throws IOException { // check if namespace is default. if (prefixMap == null) prefixMap = current.prefixMap; if (namespace == null) namespace = ""; String prefix = prefixMap.getPrefix (namespace); if (prefix == null) { //System.out.println ("namespace "+namespace +" not found in "+prefixMap); prefixMap = new PrefixMap (prefixMap, "", namespace); prefix = ""; } String tag = prefix.length () == 0 ? name : prefix + ':' + name; PrefixMap oldMap = current.prefixMap; startTag (prefixMap, tag); // if namespace has changed, write out changes... if (prefixMap != oldMap) { for (Enumeration e = prefixMap.prefixEnumeration (); e.hasMoreElements ();) { String p2 = (String) e.nextElement (); String ns = prefixMap.getNamespace (p2); if (ns != oldMap.getNamespace (p2)) { if (p2.equals ("")) attribute ("xmlns", ns); else attribute ("xmlns:"+p2, ns); } } } } /** writes a start tag with the given namespace and name */ public void startTag (String namespace, String name) throws IOException { startTag (null, namespace, name); } /** convenience method for startTag (Xml.NO_NAMESPACE, name) */ public void startTag (String name) throws IOException { startTag (null, Xml.NO_NAMESPACE, name); } /** abstract method that must be overwritten by a method actually writing the resolved start tag without namespace checking. This implementation just puts the state on the stack. Attention: The actual implementation include the following line in order to put the current State on the stack! current = new State (current, prefixMap, tag); */ protected abstract void startTag (PrefixMap prefixMap, String tag) throws IOException; /** @deprecated Old method for writing a (possibly degenerated) tag including the given attributes. Please use subsequent calls of the other methods instead! */ public void startTag (String name, String [] attrs, boolean degenerated) throws IOException { startTag (name); for (int i = 0; i < attrs.length; i+=2) attribute (attrs [i], attrs [i+1]); if (degenerated) endTag (); } /** Abstract method for writing an end tag. Attention: Concrete implementations must pop the previous state from the stack: current = current.prev; */ public abstract void endTag () throws IOException; /** writes Xml.DOCTYPE, Xml.PROCESSING_INSTRUCTION or Xml.COMMENT */ public abstract void writeLegacy (int type, String text) throws IOException; }