1 /* SAXEventSink.java --
2 Copyright (C) 1999,2000,2001 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
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)
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.
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
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
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. */
38 package gnu.xml.dom.ls;
40 import java.util.HashSet;
41 import java.util.Iterator;
42 import java.util.LinkedList;
43 import java.util.List;
44 import javax.xml.XMLConstants;
45 import org.w3c.dom.Attr;
46 import org.w3c.dom.Document;
47 import org.w3c.dom.DocumentType;
48 import org.w3c.dom.Element;
49 import org.w3c.dom.Entity;
50 import org.w3c.dom.EntityReference;
51 import org.w3c.dom.NamedNodeMap;
52 import org.w3c.dom.Node;
53 import org.w3c.dom.Text;
54 import org.xml.sax.Attributes;
55 import org.xml.sax.ContentHandler;
56 import org.xml.sax.DTDHandler;
57 import org.xml.sax.Locator;
58 import org.xml.sax.SAXException;
59 import org.xml.sax.SAXNotRecognizedException;
60 import org.xml.sax.SAXNotSupportedException;
61 import org.xml.sax.XMLReader;
62 import org.xml.sax.ext.Attributes2;
63 import org.xml.sax.ext.DeclHandler;
64 import org.xml.sax.ext.LexicalHandler;
65 import org.xml.sax.ext.Locator2;
66 import gnu.xml.dom.DomAttr;
67 import gnu.xml.dom.DomDocument;
68 import gnu.xml.dom.DomDoctype;
69 import gnu.xml.dom.DomNode;
72 * A SAX content and lexical handler used to construct a DOM document.
74 * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
76 public class SAXEventSink
77 implements ContentHandler, LexicalHandler, DTDHandler, DeclHandler
80 private static final String XMLNS_URI = XMLConstants.XMLNS_ATTRIBUTE_NS_URI;
81 private static final String XMLNS_PREFIX = XMLConstants.XMLNS_ATTRIBUTE;
82 private static final HashSet PREDEFINED_ENTITIES = new HashSet();
85 PREDEFINED_ENTITIES.add("amp");
86 PREDEFINED_ENTITIES.add("lt");
87 PREDEFINED_ENTITIES.add("gt");
88 PREDEFINED_ENTITIES.add("quot");
89 PREDEFINED_ENTITIES.add("apos");
92 boolean namespaceAware;
93 boolean ignoreWhitespace;
94 boolean expandEntityReferences;
95 boolean ignoreComments;
98 XMLReader reader; // reference back to the parser to get features
100 DomDocument doc; // document being constructed
101 Node ctx; // current context (parent node)
102 LinkedList entityCtx; // entity context
103 List pending; // namespace nodes waiting for a declaring element
114 protected Document getDocument()
119 // -- ContentHandler2 --
121 public void setDocumentLocator(Locator locator)
123 this.locator = locator;
126 public void startDocument()
131 pending = new LinkedList();
133 doc = new DomDocument();
134 doc.setStrictErrorChecking(false);
135 doc.setBuilding(true);
138 final String FEATURES = "http://xml.org/sax/features/";
139 final String PROPERTIES = "http://xml.org/sax/properties/";
140 final String GNU_PROPERTIES = "http://gnu.org/sax/properties/";
142 boolean standalone = reader.getFeature(FEATURES + "is-standalone");
143 doc.setXmlStandalone(standalone);
146 String version = (String) reader.getProperty(PROPERTIES +
147 "document-xml-version");
148 doc.setXmlVersion(version);
150 catch (SAXNotRecognizedException e)
153 catch (SAXNotSupportedException e)
156 if (locator != null && locator instanceof Locator2)
158 String encoding = ((Locator2) locator).getEncoding();
159 doc.setInputEncoding(encoding);
163 String encoding = (String) reader.getProperty(GNU_PROPERTIES +
164 "document-xml-encoding");
165 doc.setXmlEncoding(encoding);
167 catch (SAXNotRecognizedException e)
170 catch (SAXNotSupportedException e)
175 public void endDocument()
178 doc.setStrictErrorChecking(true);
179 doc.setBuilding(false);
180 DomDoctype doctype = (DomDoctype) doc.getDoctype();
183 doctype.makeReadonly();
189 public void startPrefixMapping(String prefix, String uri)
194 String nsName = (prefix != null && prefix.length() > 0) ?
195 XMLNS_PREFIX + ":" + prefix : XMLNS_PREFIX;
196 DomAttr ns = (DomAttr) doc.createAttributeNS(XMLNS_URI, nsName);
197 ns.setNodeValue(uri);
198 if (ctx.getNodeType() == Node.ATTRIBUTE_NODE)
200 // Add to owner element
201 Node target = ((Attr) ctx).getOwnerElement();
202 target.getAttributes().setNamedItemNS(ns);
206 // Add to pending list; namespace node will be inserted when
213 public void endPrefixMapping(String prefix)
218 public void startElement(String uri, String localName, String qName,
226 Element element = createElement(uri, localName, qName, atts);
227 // add element to context
228 ctx.appendChild(element);
232 protected Element createElement(String uri, String localName, String qName,
236 // create element node
237 Element element = namespaceAware ?
238 doc.createElementNS(uri, qName) :
239 doc.createElement(qName);
240 NamedNodeMap attrs = element.getAttributes();
241 if (namespaceAware && !pending.isEmpty())
243 // add pending namespace nodes
244 for (Iterator i = pending.iterator(); i.hasNext(); )
246 Node ns = (Node) i.next();
247 attrs.setNamedItemNS(ns);
252 int len = atts.getLength();
253 for (int i = 0; i < len; i++)
256 Attr attr = createAttr(atts, i);
259 // add attribute to element
262 attrs.setNamedItemNS(attr);
266 attrs.setNamedItem(attr);
273 protected Attr createAttr(Attributes atts, int index)
278 String a_uri = atts.getURI(index);
279 String a_qName = atts.getQName(index);
280 attr = (DomAttr) doc.createAttributeNS(a_uri, a_qName);
284 String a_qName = atts.getQName(index);
285 attr = (DomAttr) doc.createAttribute(a_qName);
287 attr.setNodeValue(atts.getValue(index));
288 if (atts instanceof Attributes2)
290 Attributes2 atts2 = (Attributes2) atts;
291 // TODO attr.setDeclared(atts2.isDeclared(index));
292 attr.setSpecified(atts2.isSpecified(index));
297 public void endElement(String uri, String localName, String qName)
308 ctx = ctx.getParentNode();
311 public void characters(char[] c, int off, int len)
314 if (interrupted || len < 1)
318 ctx.appendChild(createText(c, off, len));
321 protected Text createText(char[] c, int off, int len)
324 Text text = (inCDATA && !coalescing) ?
325 doc.createCDATASection(new String(c, off, len)) :
326 doc.createTextNode(new String(c, off, len));
330 public void ignorableWhitespace(char[] c, int off, int len)
337 if (!ignoreWhitespace)
339 characters(c, off, len);
343 public void processingInstruction(String target, String data)
350 Node pi = createProcessingInstruction(target, data);
354 protected Node createProcessingInstruction(String target, String data)
356 return doc.createProcessingInstruction(target, data);
359 public void skippedEntity(String name)
362 // This callback is totally pointless
365 // -- LexicalHandler --
367 public void startDTD(String name, String publicId, String systemId)
374 Node doctype = createDocumentType(name, publicId, systemId);
375 doc.appendChild(doctype);
380 protected Node createDocumentType(String name, String publicId,
383 return new DomDoctype(doc, name, publicId, systemId);
394 ctx = ctx.getParentNode();
397 public void startEntity(String name)
402 DocumentType doctype = doc.getDoctype();
405 throw new SAXException("SAX parser error: " +
406 "reference to entity in undeclared doctype");
408 if ("[dtd]".equals(name) || name.charAt(0) == '%')
410 if (PREDEFINED_ENTITIES.contains(name))
413 NamedNodeMap entities = doctype.getEntities();
414 Entity entity = (Entity) entities.getNamedItem(name);
417 throw new SAXException("SAX parser error: " +
418 "reference to undeclared entity: " + name);
420 EntityReference ref = doc.createEntityReference(name);
421 // DomDocument populates with the entity replacement text, remove this
422 Node child = ref.getFirstChild();
423 while (child != null)
425 Node nextChild = child.getNextSibling();
426 ref.removeChild(child);
429 ctx.appendChild(ref);
433 public void endEntity(String name)
438 if ("[dtd]".equals(name) || name.charAt(0) == '%')
440 if (PREDEFINED_ENTITIES.contains(name))
442 // Get entity reference
443 EntityReference ref = (EntityReference) ctx;
444 if (!ref.getNodeName().equals(name))
445 throw new SAXException("expecting end of "+ref.getNodeName()+" entity");
446 ctx = ctx.getParentNode();
447 if (ref instanceof DomNode)
448 ((DomNode) ref).makeReadonly();
449 if (expandEntityReferences)
451 // Move entity content from reference node onto context
452 Node child = ref.getFirstChild();
453 while (child != null)
455 Node nextChild = child.getNextSibling();
456 ctx.appendChild(child);
459 ctx.removeChild(ref);
463 public void startCDATA()
469 public void endCDATA()
475 public void comment(char[] c, int off, int len)
482 Node comment = createComment(c, off, len);
483 ctx.appendChild(comment);
486 protected Node createComment(char[] c, int off, int len)
488 return doc.createComment(new String(c, off, len));
493 public void notationDecl(String name, String publicId, String systemId)
501 throw new SAXException("notation decl outside DTD");
502 DomDoctype doctype = (DomDoctype) ctx;
503 doctype.declareNotation(name, publicId, systemId);
506 public void unparsedEntityDecl(String name, String publicId, String systemId,
515 throw new SAXException("unparsed entity decl outside DTD");
516 DomDoctype doctype = (DomDoctype) ctx;
517 Entity entity = doctype.declareEntity(name, publicId, systemId,
523 public void elementDecl(String name, String model)
531 throw new SAXException("element decl outside DTD");
532 // Ignore fake element declarations generated by ValidationConsumer.
533 // If an element is not really declared in the DTD it will not be
534 // declared in the document model.
535 if (!(ctx instanceof DomDoctype))
539 DomDoctype doctype = (DomDoctype) ctx;
540 doctype.elementDecl(name, model);
543 public void attributeDecl(String eName, String aName, String type,
544 String mode, String value)
552 throw new SAXException("attribute decl outside DTD");
553 DomDoctype doctype = (DomDoctype) ctx;
554 doctype.attributeDecl(eName, aName, type, mode, value);
557 public void internalEntityDecl(String name, String value)
565 throw new SAXException("internal entity decl outside DTD");
566 DomDoctype doctype = (DomDoctype) ctx;
567 Entity entity = doctype.declareEntity(name, null, null, null);
570 Node text = doc.createTextNode(value);
571 entity.appendChild(text);
575 public void externalEntityDecl(String name, String publicId, String systemId)
583 throw new SAXException("external entity decl outside DTD");
584 DomDoctype doctype = (DomDoctype) ctx;
585 Entity entity = doctype.declareEntity(name, publicId, systemId, null);