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 private 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 public Document
getDocument()
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()
141 pending
= new LinkedList();
143 doc
= new DomDocument();
144 doc
.setStrictErrorChecking(false);
145 doc
.setBuilding(true);
146 doc
.setDefaultAttributes(false);
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/";
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()
192 doc
.setStrictErrorChecking(true);
193 doc
.setBuilding(false);
194 doc
.setDefaultAttributes(true);
195 DomDoctype doctype
= (DomDoctype
) doc
.getDoctype();
198 doctype
.makeReadonly();
204 public void startPrefixMapping(String prefix
, String uri
)
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
);
221 // Add to pending list; namespace node will be inserted when
228 public void endPrefixMapping(String prefix
)
233 public void startElement(String uri
, String localName
, String qName
,
241 Element element
= createElement(uri
, localName
, qName
, atts
);
242 // add element to context
243 ctx
.appendChild(element
);
247 protected Element
createElement(String uri
, String localName
, String qName
,
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
);
267 int len
= atts
.getLength();
268 for (int i
= 0; i
< len
; i
++)
271 Attr attr
= createAttr(atts
, i
);
274 // add attribute to element
277 attrs
.setNamedItemNS(attr
);
281 attrs
.setNamedItem(attr
);
288 protected Attr
createAttr(Attributes atts
, int index
)
293 String a_uri
= atts
.getURI(index
);
294 String a_qName
= atts
.getQName(index
);
295 attr
= (DomAttr
) doc
.createAttributeNS(a_uri
, a_qName
);
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
));
312 public void endElement(String uri
, String localName
, String qName
)
323 ctx
= ctx
.getParentNode();
326 public void characters(char[] c
, int off
, int len
)
329 if (interrupted
|| len
< 1)
333 ctx
.appendChild(createText(c
, off
, len
));
336 protected Text
createText(char[] c
, int off
, int len
)
339 Text text
= (inCDATA
&& !coalescing
) ?
340 doc
.createCDATASection(new String(c
, off
, len
)) :
341 doc
.createTextNode(new String(c
, off
, len
));
345 public void ignorableWhitespace(char[] c
, int off
, int len
)
352 if (!ignoreWhitespace
)
354 characters(c
, off
, len
);
358 public void processingInstruction(String target
, String data
)
365 Node pi
= createProcessingInstruction(target
, data
);
369 protected Node
createProcessingInstruction(String target
, String data
)
371 return doc
.createProcessingInstruction(target
, data
);
374 public void skippedEntity(String name
)
377 // This callback is totally pointless
380 // -- LexicalHandler --
382 public void startDTD(String name
, String publicId
, String systemId
)
389 Node doctype
= createDocumentType(name
, publicId
, systemId
);
390 doc
.appendChild(doctype
);
395 protected Node
createDocumentType(String name
, String publicId
,
398 return new DomDoctype(doc
, name
, publicId
, systemId
);
409 ctx
= ctx
.getParentNode();
412 public void startEntity(String name
)
417 DocumentType doctype
= doc
.getDoctype();
420 throw new SAXException("SAX parser error: " +
421 "reference to entity in undeclared doctype");
423 if ("[dtd]".equals(name
) || name
.charAt(0) == '%')
425 if (PREDEFINED_ENTITIES
.contains(name
))
428 NamedNodeMap entities
= doctype
.getEntities();
429 Entity entity
= (Entity
) entities
.getNamedItem(name
);
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
);
444 ctx
.appendChild(ref
);
448 public void endEntity(String name
)
453 if ("[dtd]".equals(name
) || name
.charAt(0) == '%')
455 if (PREDEFINED_ENTITIES
.contains(name
))
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
);
474 ctx
.removeChild(ref
);
478 public void startCDATA()
484 public void endCDATA()
490 public void comment(char[] c
, int off
, int len
)
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
));
508 public void notationDecl(String name
, String publicId
, String systemId
)
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
,
530 throw new SAXException("unparsed entity decl outside DTD");
531 DomDoctype doctype
= (DomDoctype
) ctx
;
532 Entity entity
= doctype
.declareEntity(name
, publicId
, systemId
,
538 public void elementDecl(String name
, String model
)
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
))
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
)
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
)
580 throw new SAXException("internal entity decl outside DTD");
581 DomDoctype doctype
= (DomDoctype
) ctx
;
582 Entity entity
= doctype
.declareEntity(name
, null, null, null);
585 Node text
= doc
.createTextNode(value
);
586 entity
.appendChild(text
);
590 public void externalEntityDecl(String name
, String publicId
, String systemId
)
598 throw new SAXException("external entity decl outside DTD");
599 DomDoctype doctype
= (DomDoctype
) ctx
;
600 Entity entity
= doctype
.declareEntity(name
, publicId
, systemId
, null);