Merged with mainline at revision 128810.
[official-gcc.git] / libjava / classpath / gnu / xml / dom / ls / SAXEventSink.java
blob0a165aafbad57e0b478c1d5bd3603acf4b957f0b
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)
9 any later version.
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
19 02110-1301 USA.
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.
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;
71 /**
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();
83 static
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;
96 boolean coalescing;
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
104 Locator locator;
105 boolean inCDATA;
106 boolean inDTD;
107 boolean interrupted;
109 void interrupt()
111 interrupted = true;
114 public Document getDocument()
116 return doc;
119 public void setReader(XMLReader reader)
121 this.reader = reader;
124 // -- ContentHandler2 --
126 public void setDocumentLocator(Locator locator)
128 this.locator = locator;
131 public void startDocument()
132 throws SAXException
134 if (namespaceAware)
136 pending = new LinkedList();
138 doc = new DomDocument();
139 doc.setStrictErrorChecking(false);
140 doc.setBuilding(true);
141 doc.setDefaultAttributes(false);
142 ctx = doc;
144 final String FEATURES = "http://xml.org/sax/features/";
145 final String PROPERTIES = "http://xml.org/sax/properties/";
146 final String GNU_PROPERTIES = "http://gnu.org/sax/properties/";
148 if (reader != null)
150 boolean standalone = reader.getFeature(FEATURES + "is-standalone");
151 doc.setXmlStandalone(standalone);
154 String version = (String) reader.getProperty(PROPERTIES +
155 "document-xml-version");
156 doc.setXmlVersion(version);
158 catch (SAXNotRecognizedException e)
161 catch (SAXNotSupportedException e)
166 String encoding = (String) reader.getProperty(GNU_PROPERTIES +
167 "document-xml-encoding");
168 doc.setXmlEncoding(encoding);
170 catch (SAXNotRecognizedException e)
173 catch (SAXNotSupportedException e)
177 if (locator != null && locator instanceof Locator2)
179 String encoding = ((Locator2) locator).getEncoding();
180 doc.setInputEncoding(encoding);
184 public void endDocument()
185 throws SAXException
187 doc.setStrictErrorChecking(true);
188 doc.setBuilding(false);
189 doc.setDefaultAttributes(true);
190 DomDoctype doctype = (DomDoctype) doc.getDoctype();
191 if (doctype != null)
193 doctype.makeReadonly();
195 ctx = null;
196 locator = null;
199 public void startPrefixMapping(String prefix, String uri)
200 throws SAXException
202 if (namespaceAware)
204 String nsName = (prefix != null && prefix.length() > 0) ?
205 XMLNS_PREFIX + ":" + prefix : XMLNS_PREFIX;
206 DomAttr ns = (DomAttr) doc.createAttributeNS(XMLNS_URI, nsName);
207 ns.setNodeValue(uri);
208 if (ctx.getNodeType() == Node.ATTRIBUTE_NODE)
210 // Add to owner element
211 Node target = ((Attr) ctx).getOwnerElement();
212 target.getAttributes().setNamedItemNS(ns);
214 else
216 // Add to pending list; namespace node will be inserted when
217 // element is seen
218 pending.add(ns);
223 public void endPrefixMapping(String prefix)
224 throws SAXException
228 public void startElement(String uri, String localName, String qName,
229 Attributes atts)
230 throws SAXException
232 if (interrupted)
234 return;
236 Element element = createElement(uri, localName, qName, atts);
237 // add element to context
238 ctx.appendChild(element);
239 ctx = element;
242 protected Element createElement(String uri, String localName, String qName,
243 Attributes atts)
244 throws SAXException
246 // create element node
247 Element element = namespaceAware ?
248 doc.createElementNS(uri, qName) :
249 doc.createElement(qName);
250 NamedNodeMap attrs = element.getAttributes();
251 if (namespaceAware && !pending.isEmpty())
253 // add pending namespace nodes
254 for (Iterator i = pending.iterator(); i.hasNext(); )
256 Node ns = (Node) i.next();
257 attrs.setNamedItemNS(ns);
259 pending.clear();
261 // add attributes
262 int len = atts.getLength();
263 for (int i = 0; i < len; i++)
265 // create attribute
266 Attr attr = createAttr(atts, i);
267 if (attr != null)
269 // add attribute to element
270 if (namespaceAware)
272 attrs.setNamedItemNS(attr);
274 else
276 attrs.setNamedItem(attr);
280 return element;
283 protected Attr createAttr(Attributes atts, int index)
285 DomAttr attr;
286 if (namespaceAware)
288 String a_uri = atts.getURI(index);
289 String a_qName = atts.getQName(index);
290 attr = (DomAttr) doc.createAttributeNS(a_uri, a_qName);
292 else
294 String a_qName = atts.getQName(index);
295 attr = (DomAttr) doc.createAttribute(a_qName);
297 attr.setNodeValue(atts.getValue(index));
298 if (atts instanceof Attributes2)
300 Attributes2 atts2 = (Attributes2) atts;
301 // TODO attr.setDeclared(atts2.isDeclared(index));
302 attr.setSpecified(atts2.isSpecified(index));
304 return attr;
307 public void endElement(String uri, String localName, String qName)
308 throws SAXException
310 if (interrupted)
312 return;
314 if (namespaceAware)
316 pending.clear();
318 ctx = ctx.getParentNode();
321 public void characters(char[] c, int off, int len)
322 throws SAXException
324 if (interrupted || len < 1)
326 return;
328 ctx.appendChild(createText(c, off, len));
331 protected Text createText(char[] c, int off, int len)
332 throws SAXException
334 Text text = (inCDATA && !coalescing) ?
335 doc.createCDATASection(new String(c, off, len)) :
336 doc.createTextNode(new String(c, off, len));
337 return text;
340 public void ignorableWhitespace(char[] c, int off, int len)
341 throws SAXException
343 if (interrupted)
345 return;
347 if (!ignoreWhitespace)
349 characters(c, off, len);
353 public void processingInstruction(String target, String data)
354 throws SAXException
356 if (interrupted)
358 return;
360 Node pi = createProcessingInstruction(target, data);
361 ctx.appendChild(pi);
364 protected Node createProcessingInstruction(String target, String data)
366 return doc.createProcessingInstruction(target, data);
369 public void skippedEntity(String name)
370 throws SAXException
372 // This callback is totally pointless
375 // -- LexicalHandler --
377 public void startDTD(String name, String publicId, String systemId)
378 throws SAXException
380 if (interrupted)
382 return;
384 Node doctype = createDocumentType(name, publicId, systemId);
385 doc.appendChild(doctype);
386 ctx = doctype;
387 inDTD = true;
390 protected Node createDocumentType(String name, String publicId,
391 String systemId)
393 return new DomDoctype(doc, name, publicId, systemId);
396 public void endDTD()
397 throws SAXException
399 if (interrupted)
401 return;
403 inDTD = false;
404 ctx = ctx.getParentNode();
407 public void startEntity(String name)
408 throws SAXException
410 if (interrupted)
411 return;
412 DocumentType doctype = doc.getDoctype();
413 if (doctype == null)
415 throw new SAXException("SAX parser error: " +
416 "reference to entity in undeclared doctype");
418 if ("[dtd]".equals(name) || name.charAt(0) == '%')
419 return;
420 if (PREDEFINED_ENTITIES.contains(name))
421 return;
422 // Get entity
423 NamedNodeMap entities = doctype.getEntities();
424 Entity entity = (Entity) entities.getNamedItem(name);
425 if (entity == null)
427 throw new SAXException("SAX parser error: " +
428 "reference to undeclared entity: " + name);
430 EntityReference ref = doc.createEntityReference(name);
431 // DomDocument populates with the entity replacement text, remove this
432 Node child = ref.getFirstChild();
433 while (child != null)
435 Node nextChild = child.getNextSibling();
436 ref.removeChild(child);
437 child = nextChild;
439 ctx.appendChild(ref);
440 ctx = ref;
443 public void endEntity(String name)
444 throws SAXException
446 if (interrupted)
447 return;
448 if ("[dtd]".equals(name) || name.charAt(0) == '%')
449 return;
450 if (PREDEFINED_ENTITIES.contains(name))
451 return;
452 // Get entity reference
453 EntityReference ref = (EntityReference) ctx;
454 if (!ref.getNodeName().equals(name))
455 throw new SAXException("expecting end of "+ref.getNodeName()+" entity");
456 ctx = ctx.getParentNode();
457 if (ref instanceof DomNode)
458 ((DomNode) ref).makeReadonly();
459 if (expandEntityReferences)
461 // Move entity content from reference node onto context
462 Node child = ref.getFirstChild();
463 while (child != null)
465 Node nextChild = child.getNextSibling();
466 ctx.appendChild(child);
467 child = nextChild;
469 ctx.removeChild(ref);
473 public void startCDATA()
474 throws SAXException
476 inCDATA = true;
479 public void endCDATA()
480 throws SAXException
482 inCDATA = false;
485 public void comment(char[] c, int off, int len)
486 throws SAXException
488 if (interrupted)
490 return;
492 Node comment = createComment(c, off, len);
493 ctx.appendChild(comment);
496 protected Node createComment(char[] c, int off, int len)
498 return doc.createComment(new String(c, off, len));
501 // -- DTDHandler --
503 public void notationDecl(String name, String publicId, String systemId)
504 throws SAXException
506 if (interrupted)
508 return;
510 if (!inDTD)
511 throw new SAXException("notation decl outside DTD");
512 DomDoctype doctype = (DomDoctype) ctx;
513 doctype.declareNotation(name, publicId, systemId);
516 public void unparsedEntityDecl(String name, String publicId, String systemId,
517 String notationName)
518 throws SAXException
520 if (interrupted)
522 return;
524 if (!inDTD)
525 throw new SAXException("unparsed entity decl outside DTD");
526 DomDoctype doctype = (DomDoctype) ctx;
527 Entity entity = doctype.declareEntity(name, publicId, systemId,
528 notationName);
531 // -- DeclHandler --
533 public void elementDecl(String name, String model)
534 throws SAXException
536 if (interrupted)
538 return;
540 if (!inDTD)
541 throw new SAXException("element decl outside DTD");
542 // Ignore fake element declarations generated by ValidationConsumer.
543 // If an element is not really declared in the DTD it will not be
544 // declared in the document model.
545 if (!(ctx instanceof DomDoctype))
547 return;
549 DomDoctype doctype = (DomDoctype) ctx;
550 doctype.elementDecl(name, model);
553 public void attributeDecl(String eName, String aName, String type,
554 String mode, String value)
555 throws SAXException
557 if (interrupted)
559 return;
561 if (!inDTD)
562 throw new SAXException("attribute decl outside DTD");
563 DomDoctype doctype = (DomDoctype) ctx;
564 doctype.attributeDecl(eName, aName, type, mode, value);
567 public void internalEntityDecl(String name, String value)
568 throws SAXException
570 if (interrupted)
572 return;
574 if (!inDTD)
575 throw new SAXException("internal entity decl outside DTD");
576 DomDoctype doctype = (DomDoctype) ctx;
577 Entity entity = doctype.declareEntity(name, null, null, null);
578 if (entity != null)
580 Node text = doc.createTextNode(value);
581 entity.appendChild(text);
585 public void externalEntityDecl(String name, String publicId, String systemId)
586 throws SAXException
588 if (interrupted)
590 return;
592 if (!inDTD)
593 throw new SAXException("external entity decl outside DTD");
594 DomDoctype doctype = (DomDoctype) ctx;
595 Entity entity = doctype.declareEntity(name, publicId, systemId, null);