| /* Consumer.java -- |
| Copyright (C) 2001,2004 Free Software Foundation, Inc. |
| |
| This file is part of GNU Classpath. |
| |
| GNU Classpath is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 2, or (at your option) |
| any later version. |
| |
| GNU Classpath is distributed in the hope that it will be useful, but |
| WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with GNU Classpath; see the file COPYING. If not, write to the |
| Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
| 02110-1301 USA. |
| |
| Linking this library statically or dynamically with other modules is |
| making a combined work based on this library. Thus, the terms and |
| conditions of the GNU General Public License cover the whole |
| combination. |
| |
| As a special exception, the copyright holders of this library give you |
| permission to link this library with independent modules to produce an |
| executable, regardless of the license terms of these independent |
| modules, and to copy and distribute the resulting executable under |
| terms of your choice, provided that you also meet, for each linked |
| independent module, the terms and conditions of the license of that |
| module. An independent module is a module which is not derived from |
| or based on this library. If you modify this library, you may extend |
| this exception to your version of the library, but you are not |
| obligated to do so. If you do not wish to do so, delete this |
| exception statement from your version. */ |
| |
| |
| package gnu.xml.dom; |
| |
| import org.w3c.dom.DocumentType; |
| import org.w3c.dom.Node; |
| import org.w3c.dom.Text; |
| |
| import org.xml.sax.Attributes; |
| import org.xml.sax.SAXException; |
| import org.xml.sax.ext.Attributes2; |
| |
| import gnu.xml.pipeline.DomConsumer; |
| import gnu.xml.pipeline.EventConsumer; |
| |
| |
| /** |
| * Event consumer which constructs DOM documents using the implementation |
| * in this package, using SAX2 events. This packages various backdoors |
| * into this DOM implementation, as needed to address DOM requirements |
| * that can't be met by strictly conforming implementations of DOM. |
| * |
| * <p> These requirements all relate to {@link DocumentType} nodes and |
| * features of that node type. These features are normally not used, |
| * because that interface only exposes a subset of the information found |
| * in DTDs. More, that subset does not include the most important typing |
| * information. For example, it excludes element content models and |
| * attribute typing. It does expose some entity management issues, |
| * although entity management doesn't relate to document typing. |
| * |
| * <p> Note that SAX2 does not expose the literal text of the DTD's |
| * internal subset, so it will not be present in DOM trees constructed |
| * using this API. (Though with a good SAX2 implementation, it could |
| * be partially recreated...) |
| * |
| * @author David Brownell |
| */ |
| public class Consumer extends DomConsumer |
| { |
| /** |
| * Constructs an unconfigured event consumer, |
| * as a terminus in a SAX event pipeline. |
| */ |
| // used by PipelineFactory [terminus] |
| public Consumer () |
| throws SAXException |
| { |
| super (DomDocument.class); |
| setHandler (new Backdoor (this)); |
| } |
| |
| /** |
| * Constructs an unconfigured event consumer, |
| * as a stage in a SAX event pipeline. |
| */ |
| // used by PipelineFactory [filter] |
| public Consumer (EventConsumer next) |
| throws SAXException |
| { |
| super (DomDocument.class, next); |
| setHandler (new Backdoor (this)); |
| } |
| |
| /** |
| * Implements the backdoors needed by DOM. |
| * All methods in this class use implementation-specific APIs that are |
| * implied by the DOM specification (needed to implement testable |
| * behavior) but which are excluded from the DOM specification. |
| */ |
| public static class Backdoor extends DomConsumer.Handler |
| { |
| /** |
| * Constructor. |
| * @param consumer must have been initialized to use the |
| * {@link DomDocument} class (or a subclass) for |
| * constructing DOM trees |
| */ |
| protected Backdoor (DomConsumer consumer) |
| throws SAXException |
| { super (consumer); } |
| |
| // helper routine |
| private DomDoctype getDoctype () |
| throws SAXException |
| { |
| DomDocument doc = (DomDocument) getDocument (); |
| DocumentType dt = doc.getDoctype (); |
| |
| if (dt == null) |
| throw new SAXException ("doctype missing!"); |
| return (DomDoctype) dt; |
| } |
| |
| // SAX2 "lexical" event |
| public void startDTD (String name, String publicId, String systemId) |
| throws SAXException |
| { |
| DomDocument doc = (DomDocument) getDocument (); |
| |
| super.startDTD (name, publicId, systemId); |
| // DOM L2 doctype creation model is bizarre |
| DomDoctype dt = new DomDoctype (doc, name, publicId, systemId); |
| doc.appendChild (dt); |
| } |
| |
| // SAX2 "lexical" event |
| public void endDTD () |
| throws SAXException |
| { |
| super.endDTD (); |
| // DOM L2 has no way to make things readonly |
| getDoctype ().makeReadonly (); |
| } |
| |
| // SAX1 DTD event |
| public void notationDecl ( |
| String name, |
| String publicId, String systemId |
| ) throws SAXException |
| { |
| // DOM L2 can't create/save notation nodes |
| getDoctype ().declareNotation (name, publicId, systemId); |
| } |
| |
| // SAX1 DTD event |
| public void unparsedEntityDecl ( |
| String name, |
| String publicId, String systemId, |
| String notationName |
| ) throws SAXException |
| { |
| // DOM L2 can't create/save entity nodes |
| getDoctype ().declareEntity (name, publicId, systemId, |
| notationName); |
| } |
| |
| // SAX2 declaration event |
| public void internalEntityDecl (String name, String value) |
| throws SAXException |
| { |
| // DOM L2 can't create/save entity nodes |
| // NOTE: this doesn't save the value as a child of this |
| // node, though it could realistically do so. |
| getDoctype ().declareEntity (name, null, null, null); |
| } |
| |
| // SAX2 declaration event |
| public void externalEntityDecl ( |
| String name, |
| String publicId, |
| String systemId |
| ) throws SAXException |
| { |
| // DOM L2 can't create/save entity nodes |
| // NOTE: DOM allows for these to have children, if |
| // they don't have unbound namespace references. |
| getDoctype ().declareEntity (name, publicId, systemId, null); |
| } |
| |
| // SAX2 element |
| public void startElement ( |
| String uri, |
| String localName, |
| String qName, |
| Attributes atts |
| ) throws SAXException |
| { |
| Node top; |
| |
| super.startElement (uri, localName, qName, atts); |
| |
| // might there be more work? |
| top = getTop (); |
| if (!top.hasAttributes () || !(atts instanceof Attributes2)) |
| return; |
| |
| // remember any attributes that got defaulted |
| DomNamedNodeMap map = (DomNamedNodeMap) top.getAttributes (); |
| Attributes2 attrs = (Attributes2) atts; |
| int length = atts.getLength (); |
| |
| //map.compact (); |
| for (int i = 0; i < length; i++) { |
| if (attrs.isSpecified (i)) |
| continue; |
| |
| // value was defaulted. |
| String temp = attrs.getQName (i); |
| DomAttr attr; |
| |
| if ("".equals (temp)) |
| attr = (DomAttr) map.getNamedItemNS (attrs.getURI (i), |
| atts.getLocalName (i)); |
| else |
| attr = (DomAttr) map.getNamedItem (temp); |
| |
| // DOM L2 can't write this flag, only read it |
| attr.setSpecified (false); |
| } |
| } |
| |
| public void endElement ( |
| String uri, |
| String localName, |
| String qName |
| ) throws SAXException |
| { |
| DomNode top = (DomNode) getTop (); |
| top.compact (); |
| super.endElement (uri, localName, qName); |
| } |
| |
| protected Text createText ( |
| boolean isCDATA, |
| char buf [], |
| int off, |
| int len |
| ) { |
| DomDocument doc = (DomDocument) getDocument (); |
| |
| if (isCDATA) |
| return doc.createCDATASection (buf, off, len); |
| else |
| return doc.createTextNode (buf, off, len); |
| } |
| |
| public void elementDecl(String name, String model) |
| throws SAXException |
| { |
| getDoctype().elementDecl(name, model); |
| } |
| |
| public void attributeDecl ( |
| String ename, |
| String aname, |
| String type, |
| String mode, |
| String value |
| ) throws SAXException |
| { |
| getDoctype().attributeDecl(ename, aname, type, mode, value); |
| /* |
| if (value == null && !"ID".equals (type)) |
| return; |
| |
| DomDoctype.ElementInfo info; |
| |
| info = getDoctype ().getElementInfo (ename); |
| if (value != null) |
| info.setAttrDefault (aname, value); |
| if ("ID".equals (type)) |
| info.setIdAttr (aname); |
| */ |
| |
| } |
| |
| // force duplicate name checking off while we're |
| // using parser output (don't duplicate the work) |
| public void startDocument () throws SAXException |
| { |
| super.startDocument (); |
| |
| DomDocument doc = (DomDocument) getDocument (); |
| doc.setStrictErrorChecking(false); |
| doc.setBuilding(true); |
| } |
| |
| public void endDocument () |
| throws SAXException |
| { |
| DomDocument doc = (DomDocument) getDocument (); |
| doc.setStrictErrorChecking(true); |
| doc.setBuilding(false); |
| doc.compact (); |
| DomDoctype doctype = (DomDoctype) doc.getDoctype(); |
| if (doctype != null) |
| { |
| doctype.makeReadonly(); |
| } |
| super.endDocument (); |
| } |
| |
| // these three methods collaborate to populate entity |
| // refs, marking contents readonly on end-of-entity |
| |
| public boolean canPopulateEntityRefs () |
| { return true; } |
| |
| public void startEntity (String name) |
| throws SAXException |
| { |
| if (name.charAt (0) == '%' || "[dtd]".equals (name)) |
| return; |
| super.startEntity (name); |
| |
| DomNode top = (DomNode) getTop (); |
| |
| if (top.getNodeType () == Node.ENTITY_REFERENCE_NODE) |
| top.readonly = false; |
| } |
| |
| public void endEntity (String name) |
| throws SAXException |
| { |
| if (name.charAt (0) == '%' || "[dtd]".equals (name)) |
| return; |
| DomNode top = (DomNode) getTop (); |
| |
| if (top.getNodeType () == Node.ENTITY_REFERENCE_NODE) { |
| top.compact (); |
| top.makeReadonly (); |
| } |
| super.endEntity (name); |
| } |
| } |
| } |