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 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 startDocument()
136 pending
= new LinkedList();
138 doc
= new DomDocument();
139 doc
.setStrictErrorChecking(false);
140 doc
.setBuilding(true);
141 doc
.setDefaultAttributes(false);
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/";
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()
187 doc
.setStrictErrorChecking(true);
188 doc
.setBuilding(false);
189 doc
.setDefaultAttributes(true);
190 DomDoctype doctype
= (DomDoctype
) doc
.getDoctype();
193 doctype
.makeReadonly();
199 public void startPrefixMapping(String prefix
, String uri
)
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
);
216 // Add to pending list; namespace node will be inserted when
223 public void endPrefixMapping(String prefix
)
228 public void startElement(String uri
, String localName
, String qName
,
236 Element element
= createElement(uri
, localName
, qName
, atts
);
237 // add element to context
238 ctx
.appendChild(element
);
242 protected Element
createElement(String uri
, String localName
, String qName
,
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
);
262 int len
= atts
.getLength();
263 for (int i
= 0; i
< len
; i
++)
266 Attr attr
= createAttr(atts
, i
);
269 // add attribute to element
272 attrs
.setNamedItemNS(attr
);
276 attrs
.setNamedItem(attr
);
283 protected Attr
createAttr(Attributes atts
, int index
)
288 String a_uri
= atts
.getURI(index
);
289 String a_qName
= atts
.getQName(index
);
290 attr
= (DomAttr
) doc
.createAttributeNS(a_uri
, a_qName
);
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
));
307 public void endElement(String uri
, String localName
, String qName
)
318 ctx
= ctx
.getParentNode();
321 public void characters(char[] c
, int off
, int len
)
324 if (interrupted
|| len
< 1)
328 ctx
.appendChild(createText(c
, off
, len
));
331 protected Text
createText(char[] c
, int off
, int len
)
334 Text text
= (inCDATA
&& !coalescing
) ?
335 doc
.createCDATASection(new String(c
, off
, len
)) :
336 doc
.createTextNode(new String(c
, off
, len
));
340 public void ignorableWhitespace(char[] c
, int off
, int len
)
347 if (!ignoreWhitespace
)
349 characters(c
, off
, len
);
353 public void processingInstruction(String target
, String data
)
360 Node pi
= createProcessingInstruction(target
, data
);
364 protected Node
createProcessingInstruction(String target
, String data
)
366 return doc
.createProcessingInstruction(target
, data
);
369 public void skippedEntity(String name
)
372 // This callback is totally pointless
375 // -- LexicalHandler --
377 public void startDTD(String name
, String publicId
, String systemId
)
384 Node doctype
= createDocumentType(name
, publicId
, systemId
);
385 doc
.appendChild(doctype
);
390 protected Node
createDocumentType(String name
, String publicId
,
393 return new DomDoctype(doc
, name
, publicId
, systemId
);
404 ctx
= ctx
.getParentNode();
407 public void startEntity(String name
)
412 DocumentType doctype
= doc
.getDoctype();
415 throw new SAXException("SAX parser error: " +
416 "reference to entity in undeclared doctype");
418 if ("[dtd]".equals(name
) || name
.charAt(0) == '%')
420 if (PREDEFINED_ENTITIES
.contains(name
))
423 NamedNodeMap entities
= doctype
.getEntities();
424 Entity entity
= (Entity
) entities
.getNamedItem(name
);
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
);
439 ctx
.appendChild(ref
);
443 public void endEntity(String name
)
448 if ("[dtd]".equals(name
) || name
.charAt(0) == '%')
450 if (PREDEFINED_ENTITIES
.contains(name
))
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
);
469 ctx
.removeChild(ref
);
473 public void startCDATA()
479 public void endCDATA()
485 public void comment(char[] c
, int off
, int len
)
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
));
503 public void notationDecl(String name
, String publicId
, String systemId
)
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
,
525 throw new SAXException("unparsed entity decl outside DTD");
526 DomDoctype doctype
= (DomDoctype
) ctx
;
527 Entity entity
= doctype
.declareEntity(name
, publicId
, systemId
,
533 public void elementDecl(String name
, String model
)
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
))
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
)
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
)
575 throw new SAXException("internal entity decl outside DTD");
576 DomDoctype doctype
= (DomDoctype
) ctx
;
577 Entity entity
= doctype
.declareEntity(name
, null, null, null);
580 Node text
= doc
.createTextNode(value
);
581 entity
.appendChild(text
);
585 public void externalEntityDecl(String name
, String publicId
, String systemId
)
593 throw new SAXException("external entity decl outside DTD");
594 DomDoctype doctype
= (DomDoctype
) ctx
;
595 Entity entity
= doctype
.declareEntity(name
, publicId
, systemId
, null);