Source for gnu.xml.dom.Consumer

   1: /* Consumer.java --
   2:    Copyright (C) 2001,2004 Free Software Foundation, Inc.
   3: 
   4: This file is part of GNU Classpath.
   5: 
   6: GNU Classpath is free software; you can redistribute it and/or modify
   7: it under the terms of the GNU General Public License as published by
   8: the Free Software Foundation; either version 2, or (at your option)
   9: any later version.
  10: 
  11: GNU Classpath is distributed in the hope that it will be useful, but
  12: WITHOUT ANY WARRANTY; without even the implied warranty of
  13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14: General Public License for more details.
  15: 
  16: You should have received a copy of the GNU General Public License
  17: along with GNU Classpath; see the file COPYING.  If not, write to the
  18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  19: 02110-1301 USA.
  20: 
  21: Linking this library statically or dynamically with other modules is
  22: making a combined work based on this library.  Thus, the terms and
  23: conditions of the GNU General Public License cover the whole
  24: combination.
  25: 
  26: As a special exception, the copyright holders of this library give you
  27: permission to link this library with independent modules to produce an
  28: executable, regardless of the license terms of these independent
  29: modules, and to copy and distribute the resulting executable under
  30: terms of your choice, provided that you also meet, for each linked
  31: independent module, the terms and conditions of the license of that
  32: module.  An independent module is a module which is not derived from
  33: or based on this library.  If you modify this library, you may extend
  34: this exception to your version of the library, but you are not
  35: obligated to do so.  If you do not wish to do so, delete this
  36: exception statement from your version. */
  37: 
  38: 
  39: package gnu.xml.dom;
  40: 
  41: import org.w3c.dom.DocumentType;
  42: import org.w3c.dom.Node;
  43: import org.w3c.dom.Text;
  44: 
  45: import org.xml.sax.Attributes;
  46: import org.xml.sax.SAXException;
  47: import org.xml.sax.ext.Attributes2;
  48: 
  49: import gnu.xml.pipeline.DomConsumer;
  50: import gnu.xml.pipeline.EventConsumer;
  51: 
  52: 
  53: /**
  54:  * Event consumer which constructs DOM documents using the implementation
  55:  * in this package, using SAX2 events.  This packages various backdoors
  56:  * into this DOM implementation, as needed to address DOM requirements
  57:  * that can't be met by strictly conforming implementations of DOM.
  58:  *
  59:  * <p> These requirements all relate to {@link DocumentType} nodes and
  60:  * features of that node type.  These features are normally not used,
  61:  * because that interface only exposes a subset of the information found
  62:  * in DTDs.  More, that subset does not include the most important typing
  63:  * information.  For example, it excludes element content models and
  64:  * attribute typing.  It does expose some entity management issues,
  65:  * although entity management doesn't relate to document typing.
  66:  *
  67:  * <p> Note that SAX2 does not expose the literal text of the DTD's
  68:  * internal subset, so it will not be present in DOM trees constructed
  69:  * using this API.  (Though with a good SAX2 implementation, it could
  70:  * be partially recreated...)
  71:  *
  72:  * @author David Brownell
  73:  */
  74: public class Consumer extends DomConsumer
  75: {
  76:     /**
  77:      * Constructs an unconfigured event consumer,
  78:      * as a terminus in a SAX event pipeline.
  79:      */
  80:     // used by PipelineFactory [terminus]
  81:     public Consumer ()
  82:     throws SAXException
  83:     {
  84:         super (DomDocument.class);
  85:         setHandler (new Backdoor (this));
  86:     }
  87: 
  88:     /**
  89:      * Constructs an unconfigured event consumer,
  90:      * as a stage in a SAX event pipeline.
  91:      */
  92:     // used by PipelineFactory [filter]
  93:     public Consumer (EventConsumer next)
  94:     throws SAXException
  95:     {
  96:         super (DomDocument.class, next);
  97:         setHandler (new Backdoor (this));
  98:     }
  99: 
 100:     /**
 101:      * Implements the backdoors needed by DOM.
 102:      * All methods in this class use implementation-specific APIs that are
 103:      * implied by the DOM specification (needed to implement testable
 104:      * behavior) but which are excluded from the DOM specification.
 105:      */
 106:     public static class Backdoor extends DomConsumer.Handler
 107:     {
 108:         /**
 109:          * Constructor.
 110:          * @param consumer must have been initialized to use the
 111:          *      {@link DomDocument} class (or a subclass) for
 112:          *      constructing DOM trees
 113:          */
 114:         protected Backdoor (DomConsumer consumer)
 115:         throws SAXException
 116:             { super (consumer); }
 117: 
 118:         // helper routine
 119:         private DomDoctype getDoctype ()
 120:         throws SAXException
 121:         {
 122:             DomDocument         doc = (DomDocument) getDocument ();
 123:             DocumentType        dt = doc.getDoctype ();
 124: 
 125:             if (dt == null)
 126:                 throw new SAXException ("doctype missing!");
 127:             return (DomDoctype) dt;
 128:         }
 129: 
 130:         // SAX2 "lexical" event
 131:         public void startDTD (String name, String publicId, String systemId)
 132:         throws SAXException
 133:         {
 134:             DomDocument         doc = (DomDocument) getDocument ();
 135: 
 136:             super.startDTD (name, publicId, systemId);
 137:             // DOM L2 doctype creation model is bizarre
 138:             DomDoctype dt = new DomDoctype (doc, name, publicId, systemId);
 139:             doc.appendChild (dt);
 140:         }
 141: 
 142:         // SAX2 "lexical" event
 143:         public void endDTD ()
 144:         throws SAXException
 145:         {
 146:             super.endDTD ();
 147:             // DOM L2 has no way to make things readonly
 148:             getDoctype ().makeReadonly ();
 149:         }
 150: 
 151:         // SAX1 DTD event
 152:         public void notationDecl (
 153:             String name,
 154:             String publicId, String systemId
 155:         ) throws SAXException
 156:         {
 157:             // DOM L2 can't create/save notation nodes
 158:             getDoctype ().declareNotation (name, publicId, systemId);
 159:         }
 160: 
 161:         // SAX1 DTD event
 162:         public void unparsedEntityDecl (
 163:             String name,
 164:             String publicId, String systemId,
 165:             String notationName
 166:         ) throws SAXException
 167:         {
 168:             // DOM L2 can't create/save entity nodes
 169:             getDoctype ().declareEntity (name, publicId, systemId,
 170:                 notationName);
 171:         }
 172: 
 173:         // SAX2 declaration event
 174:         public void internalEntityDecl (String name, String value)
 175:         throws SAXException
 176:         {
 177:             // DOM L2 can't create/save entity nodes
 178:             // NOTE:  this doesn't save the value as a child of this
 179:             // node, though it could realistically do so.
 180:             getDoctype ().declareEntity (name, null, null, null);
 181:         }
 182: 
 183:         // SAX2 declaration event
 184:         public void externalEntityDecl (
 185:             String name,
 186:             String publicId,
 187:             String systemId
 188:         ) throws SAXException
 189:         {
 190:             // DOM L2 can't create/save entity nodes
 191:             // NOTE:  DOM allows for these to have children, if
 192:             // they don't have unbound namespace references.
 193:             getDoctype ().declareEntity (name, publicId, systemId, null);
 194:         }
 195: 
 196:         // SAX2 element
 197:         public void startElement (
 198:             String uri,
 199:             String localName,
 200:             String qName,
 201:             Attributes atts
 202:         ) throws SAXException
 203:         {
 204:             Node                top;
 205: 
 206:             super.startElement (uri, localName, qName, atts);
 207: 
 208:             // might there be more work?
 209:             top = getTop ();
 210:             if (!top.hasAttributes () || !(atts instanceof Attributes2))
 211:                 return;
 212: 
 213:             // remember any attributes that got defaulted
 214:             DomNamedNodeMap     map = (DomNamedNodeMap) top.getAttributes ();
 215:             Attributes2         attrs = (Attributes2) atts;
 216:             int                 length = atts.getLength ();
 217: 
 218:             //map.compact ();
 219:             for (int i = 0; i < length; i++) {
 220:                 if (attrs.isSpecified (i))
 221:                     continue;
 222: 
 223:                 // value was defaulted.
 224:                 String          temp = attrs.getQName (i);
 225:                 DomAttr         attr;
 226: 
 227:                 if ("".equals (temp))
 228:                     attr = (DomAttr) map.getNamedItemNS (attrs.getURI (i),
 229:                             atts.getLocalName (i));
 230:                 else
 231:                     attr = (DomAttr) map.getNamedItem (temp);
 232: 
 233:                 // DOM L2 can't write this flag, only read it
 234:                 attr.setSpecified (false);
 235:             }
 236:         }
 237: 
 238:         public void endElement (
 239:             String uri,
 240:             String localName,
 241:             String qName
 242:         ) throws SAXException
 243:         {
 244:             DomNode     top = (DomNode) getTop ();
 245:             top.compact ();
 246:             super.endElement (uri, localName, qName);
 247:         }
 248: 
 249:         protected Text createText (
 250:             boolean     isCDATA,
 251:             char        buf [],
 252:             int         off,
 253:             int         len
 254:         ) {
 255:             DomDocument doc = (DomDocument) getDocument ();
 256: 
 257:             if (isCDATA)
 258:                 return doc.createCDATASection (buf, off, len);
 259:             else
 260:                 return doc.createTextNode (buf, off, len);
 261:         }
 262: 
 263:         public void elementDecl(String name, String model)
 264:           throws SAXException
 265:         {
 266:           getDoctype().elementDecl(name, model);
 267:         }
 268: 
 269:         public void attributeDecl (
 270:             String      ename,
 271:             String      aname,
 272:             String      type,
 273:             String      mode,
 274:             String      value
 275:         ) throws SAXException
 276:         {
 277:           getDoctype().attributeDecl(ename, aname, type, mode, value);
 278:             /*
 279:             if (value == null && !"ID".equals (type))
 280:                 return;
 281: 
 282:             DomDoctype.ElementInfo      info;
 283: 
 284:             info = getDoctype ().getElementInfo (ename);
 285:             if (value != null)
 286:                 info.setAttrDefault (aname, value);
 287:             if ("ID".equals (type))
 288:                 info.setIdAttr (aname);
 289:                 */
 290: 
 291:         }
 292: 
 293:         // force duplicate name checking off while we're
 294:         // using parser output (don't duplicate the work)
 295:         public void startDocument () throws SAXException
 296:         {
 297:             super.startDocument ();
 298: 
 299:             DomDocument doc = (DomDocument) getDocument ();
 300:             doc.setStrictErrorChecking(false);
 301:             doc.setBuilding(true);
 302:         }
 303: 
 304:         public void endDocument ()
 305:         throws SAXException
 306:         {
 307:             DomDocument doc = (DomDocument) getDocument ();
 308:             doc.setStrictErrorChecking(true);
 309:             doc.setBuilding(false);
 310:             doc.compact ();
 311:             DomDoctype doctype = (DomDoctype) doc.getDoctype();
 312:             if (doctype != null)
 313:               {
 314:                 doctype.makeReadonly();
 315:               }
 316:             super.endDocument ();
 317:         }
 318: 
 319:         // these three methods collaborate to populate entity
 320:         // refs, marking contents readonly on end-of-entity
 321: 
 322:         public boolean canPopulateEntityRefs ()
 323:             { return true; }
 324: 
 325:         public void startEntity (String name)
 326:         throws SAXException
 327:         {
 328:             if (name.charAt (0) == '%' || "[dtd]".equals (name))
 329:                 return;
 330:             super.startEntity (name);
 331: 
 332:             DomNode     top = (DomNode) getTop ();
 333: 
 334:             if (top.getNodeType () == Node.ENTITY_REFERENCE_NODE)
 335:                 top.readonly = false;
 336:         }
 337: 
 338:         public void endEntity (String name)
 339:         throws SAXException
 340:         {
 341:             if (name.charAt (0) == '%' || "[dtd]".equals (name))
 342:                 return;
 343:             DomNode     top = (DomNode) getTop ();
 344: 
 345:             if (top.getNodeType () == Node.ENTITY_REFERENCE_NODE) {
 346:                 top.compact ();
 347:                 top.makeReadonly ();
 348:             }
 349:             super.endEntity (name);
 350:         }
 351:     }
 352: }