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, PrefixMap.DEFAULT, //null, null, null); /** 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) { PrefixMap current = prefixMap; do { String p2 = current.getPrefix (); String ns = current.getNamespace (); if (prefixMap.getNamespace (p2).equals (ns) && !ns.equals (oldMap.getNamespace (p2))) attribute (p2.equals ("") ? "xmlns" : ("xmlns:"+p2), ns); current = current.getPrevious (); } while (current != null && current != oldMap); } } /** 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; /** Abstract method for writing an end tag. Attention: Concrete implementations must pop the previous stack 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; }