libjava/ChangeLog:
[official-gcc.git] / libjava / classpath / gnu / xml / dom / ls / SAXEventSink.java
blob1f8de046d42f77cd5ad021a8adf42d8f4eec6378
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 private 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 setNamespaceAware(boolean namespaceAware)
133 this.namespaceAware = namespaceAware;
136 public void startDocument()
137 throws SAXException
139 if (namespaceAware)
141 pending = new LinkedList();
143 doc = new DomDocument();
144 doc.setStrictErrorChecking(false);
145 doc.setBuilding(true);
146 doc.setDefaultAttributes(false);
147 ctx = doc;
149 final String FEATURES = "http://xml.org/sax/features/";
150 final String PROPERTIES = "http://xml.org/sax/properties/";
151 final String GNU_PROPERTIES = "http://gnu.org/sax/properties/";
153 if (reader != null)
155 boolean standalone = reader.getFeature(FEATURES + "is-standalone");
156 doc.setXmlStandalone(standalone);
159 String version = (String) reader.getProperty(PROPERTIES +
160 "document-xml-version");
161 doc.setXmlVersion(version);
163 catch (SAXNotRecognizedException e)
166 catch (SAXNotSupportedException e)
171 String encoding = (String) reader.getProperty(GNU_PROPERTIES +
172 "document-xml-encoding");
173 doc.setXmlEncoding(encoding);
175 catch (SAXNotRecognizedException e)
178 catch (SAXNotSupportedException e)
182 if (locator != null && locator instanceof Locator2)
184 String encoding = ((Locator2) locator).getEncoding();
185 doc.setInputEncoding(encoding);
189 public void endDocument()
190 throws SAXException
192 doc.setStrictErrorChecking(true);
193 doc.setBuilding(false);
194 doc.setDefaultAttributes(true);
195 DomDoctype doctype = (DomDoctype) doc.getDoctype();
196 if (doctype != null)
198 doctype.makeReadonly();
200 ctx = null;
201 locator = null;
204 public void startPrefixMapping(String prefix, String uri)
205 throws SAXException
207 if (namespaceAware)
209 String nsName = (prefix != null && prefix.length() > 0) ?
210 XMLNS_PREFIX + ":" + prefix : XMLNS_PREFIX;
211 DomAttr ns = (DomAttr) doc.createAttributeNS(XMLNS_URI, nsName);
212 ns.setNodeValue(uri);
213 if (ctx.getNodeType() == Node.ATTRIBUTE_NODE)
215 // Add to owner element
216 Node target = ((Attr) ctx).getOwnerElement();
217 target.getAttributes().setNamedItemNS(ns);
219 else
221 // Add to pending list; namespace node will be inserted when
222 // element is seen
223 pending.add(ns);
228 public void endPrefixMapping(String prefix)
229 throws SAXException
233 public void startElement(String uri, String localName, String qName,
234 Attributes atts)
235 throws SAXException
237 if (interrupted)
239 return;
241 Element element = createElement(uri, localName, qName, atts);
242 // add element to context
243 ctx.appendChild(element);
244 ctx = element;
247 protected Element createElement(String uri, String localName, String qName,
248 Attributes atts)
249 throws SAXException
251 // create element node
252 Element element = namespaceAware ?
253 doc.createElementNS(uri, qName) :
254 doc.createElement(qName);
255 NamedNodeMap attrs = element.getAttributes();
256 if (namespaceAware && !pending.isEmpty())
258 // add pending namespace nodes
259 for (Iterator i = pending.iterator(); i.hasNext(); )
261 Node ns = (Node) i.next();
262 attrs.setNamedItemNS(ns);
264 pending.clear();
266 // add attributes
267 int len = atts.getLength();
268 for (int i = 0; i < len; i++)
270 // create attribute
271 Attr attr = createAttr(atts, i);
272 if (attr != null)
274 // add attribute to element
275 if (namespaceAware)
277 attrs.setNamedItemNS(attr);
279 else
281 attrs.setNamedItem(attr);
285 return element;
288 protected Attr createAttr(Attributes atts, int index)
290 DomAttr attr;
291 if (namespaceAware)
293 String a_uri = atts.getURI(index);
294 String a_qName = atts.getQName(index);
295 attr = (DomAttr) doc.createAttributeNS(a_uri, a_qName);
297 else
299 String a_qName = atts.getQName(index);
300 attr = (DomAttr) doc.createAttribute(a_qName);
302 attr.setNodeValue(atts.getValue(index));
303 if (atts instanceof Attributes2)
305 Attributes2 atts2 = (Attributes2) atts;
306 // TODO attr.setDeclared(atts2.isDeclared(index));
307 attr.setSpecified(atts2.isSpecified(index));
309 return attr;
312 public void endElement(String uri, String localName, String qName)
313 throws SAXException
315 if (interrupted)
317 return;
319 if (namespaceAware)
321 pending.clear();
323 ctx = ctx.getParentNode();
326 public void characters(char[] c, int off, int len)
327 throws SAXException
329 if (interrupted || len < 1)
331 return;
333 ctx.appendChild(createText(c, off, len));
336 protected Text createText(char[] c, int off, int len)
337 throws SAXException
339 Text text = (inCDATA && !coalescing) ?
340 doc.createCDATASection(new String(c, off, len)) :
341 doc.createTextNode(new String(c, off, len));
342 return text;
345 public void ignorableWhitespace(char[] c, int off, int len)
346 throws SAXException
348 if (interrupted)
350 return;
352 if (!ignoreWhitespace)
354 characters(c, off, len);
358 public void processingInstruction(String target, String data)
359 throws SAXException
361 if (interrupted)
363 return;
365 Node pi = createProcessingInstruction(target, data);
366 ctx.appendChild(pi);
369 protected Node createProcessingInstruction(String target, String data)
371 return doc.createProcessingInstruction(target, data);
374 public void skippedEntity(String name)
375 throws SAXException
377 // This callback is totally pointless
380 // -- LexicalHandler --
382 public void startDTD(String name, String publicId, String systemId)
383 throws SAXException
385 if (interrupted)
387 return;
389 Node doctype = createDocumentType(name, publicId, systemId);
390 doc.appendChild(doctype);
391 ctx = doctype;
392 inDTD = true;
395 protected Node createDocumentType(String name, String publicId,
396 String systemId)
398 return new DomDoctype(doc, name, publicId, systemId);
401 public void endDTD()
402 throws SAXException
404 if (interrupted)
406 return;
408 inDTD = false;
409 ctx = ctx.getParentNode();
412 public void startEntity(String name)
413 throws SAXException
415 if (interrupted)
416 return;
417 DocumentType doctype = doc.getDoctype();
418 if (doctype == null)
420 throw new SAXException("SAX parser error: " +
421 "reference to entity in undeclared doctype");
423 if ("[dtd]".equals(name) || name.charAt(0) == '%')
424 return;
425 if (PREDEFINED_ENTITIES.contains(name))
426 return;
427 // Get entity
428 NamedNodeMap entities = doctype.getEntities();
429 Entity entity = (Entity) entities.getNamedItem(name);
430 if (entity == null)
432 throw new SAXException("SAX parser error: " +
433 "reference to undeclared entity: " + name);
435 EntityReference ref = doc.createEntityReference(name);
436 // DomDocument populates with the entity replacement text, remove this
437 Node child = ref.getFirstChild();
438 while (child != null)
440 Node nextChild = child.getNextSibling();
441 ref.removeChild(child);
442 child = nextChild;
444 ctx.appendChild(ref);
445 ctx = ref;
448 public void endEntity(String name)
449 throws SAXException
451 if (interrupted)
452 return;
453 if ("[dtd]".equals(name) || name.charAt(0) == '%')
454 return;
455 if (PREDEFINED_ENTITIES.contains(name))
456 return;
457 // Get entity reference
458 EntityReference ref = (EntityReference) ctx;
459 if (!ref.getNodeName().equals(name))
460 throw new SAXException("expecting end of "+ref.getNodeName()+" entity");
461 ctx = ctx.getParentNode();
462 if (ref instanceof DomNode)
463 ((DomNode) ref).makeReadonly();
464 if (expandEntityReferences)
466 // Move entity content from reference node onto context
467 Node child = ref.getFirstChild();
468 while (child != null)
470 Node nextChild = child.getNextSibling();
471 ctx.appendChild(child);
472 child = nextChild;
474 ctx.removeChild(ref);
478 public void startCDATA()
479 throws SAXException
481 inCDATA = true;
484 public void endCDATA()
485 throws SAXException
487 inCDATA = false;
490 public void comment(char[] c, int off, int len)
491 throws SAXException
493 if (interrupted)
495 return;
497 Node comment = createComment(c, off, len);
498 ctx.appendChild(comment);
501 protected Node createComment(char[] c, int off, int len)
503 return doc.createComment(new String(c, off, len));
506 // -- DTDHandler --
508 public void notationDecl(String name, String publicId, String systemId)
509 throws SAXException
511 if (interrupted)
513 return;
515 if (!inDTD)
516 throw new SAXException("notation decl outside DTD");
517 DomDoctype doctype = (DomDoctype) ctx;
518 doctype.declareNotation(name, publicId, systemId);
521 public void unparsedEntityDecl(String name, String publicId, String systemId,
522 String notationName)
523 throws SAXException
525 if (interrupted)
527 return;
529 if (!inDTD)
530 throw new SAXException("unparsed entity decl outside DTD");
531 DomDoctype doctype = (DomDoctype) ctx;
532 Entity entity = doctype.declareEntity(name, publicId, systemId,
533 notationName);
536 // -- DeclHandler --
538 public void elementDecl(String name, String model)
539 throws SAXException
541 if (interrupted)
543 return;
545 if (!inDTD)
546 throw new SAXException("element decl outside DTD");
547 // Ignore fake element declarations generated by ValidationConsumer.
548 // If an element is not really declared in the DTD it will not be
549 // declared in the document model.
550 if (!(ctx instanceof DomDoctype))
552 return;
554 DomDoctype doctype = (DomDoctype) ctx;
555 doctype.elementDecl(name, model);
558 public void attributeDecl(String eName, String aName, String type,
559 String mode, String value)
560 throws SAXException
562 if (interrupted)
564 return;
566 if (!inDTD)
567 throw new SAXException("attribute decl outside DTD");
568 DomDoctype doctype = (DomDoctype) ctx;
569 doctype.attributeDecl(eName, aName, type, mode, value);
572 public void internalEntityDecl(String name, String value)
573 throws SAXException
575 if (interrupted)
577 return;
579 if (!inDTD)
580 throw new SAXException("internal entity decl outside DTD");
581 DomDoctype doctype = (DomDoctype) ctx;
582 Entity entity = doctype.declareEntity(name, null, null, null);
583 if (entity != null)
585 Node text = doc.createTextNode(value);
586 entity.appendChild(text);
590 public void externalEntityDecl(String name, String publicId, String systemId)
591 throws SAXException
593 if (interrupted)
595 return;
597 if (!inDTD)
598 throw new SAXException("external entity decl outside DTD");
599 DomDoctype doctype = (DomDoctype) ctx;
600 Entity entity = doctype.declareEntity(name, publicId, systemId, null);