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
.DocumentType
;
47 import org
.w3c
.dom
.Element
;
48 import org
.w3c
.dom
.Entity
;
49 import org
.w3c
.dom
.EntityReference
;
50 import org
.w3c
.dom
.NamedNodeMap
;
51 import org
.w3c
.dom
.Node
;
52 import org
.w3c
.dom
.Text
;
53 import org
.xml
.sax
.Attributes
;
54 import org
.xml
.sax
.ContentHandler
;
55 import org
.xml
.sax
.DTDHandler
;
56 import org
.xml
.sax
.Locator
;
57 import org
.xml
.sax
.SAXException
;
58 import org
.xml
.sax
.SAXNotRecognizedException
;
59 import org
.xml
.sax
.SAXNotSupportedException
;
60 import org
.xml
.sax
.XMLReader
;
61 import org
.xml
.sax
.ext
.Attributes2
;
62 import org
.xml
.sax
.ext
.DeclHandler
;
63 import org
.xml
.sax
.ext
.LexicalHandler
;
64 import org
.xml
.sax
.ext
.Locator2
;
65 import gnu
.xml
.dom
.DomAttr
;
66 import gnu
.xml
.dom
.DomDocument
;
67 import gnu
.xml
.dom
.DomDoctype
;
68 import gnu
.xml
.dom
.DomNode
;
71 * A SAX content and lexical handler used to construct a DOM document.
73 * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
76 implements ContentHandler
, LexicalHandler
, DTDHandler
, DeclHandler
79 private static final String XMLNS_URI
= XMLConstants
.XMLNS_ATTRIBUTE_NS_URI
;
80 private static final String XMLNS_PREFIX
= XMLConstants
.XMLNS_ATTRIBUTE
;
81 private static final HashSet PREDEFINED_ENTITIES
= new HashSet();
84 PREDEFINED_ENTITIES
.add("amp");
85 PREDEFINED_ENTITIES
.add("lt");
86 PREDEFINED_ENTITIES
.add("gt");
87 PREDEFINED_ENTITIES
.add("quot");
88 PREDEFINED_ENTITIES
.add("apos");
91 boolean namespaceAware
;
92 boolean ignoreWhitespace
;
93 boolean expandEntityReferences
;
94 boolean ignoreComments
;
97 XMLReader reader
; // reference back to the parser to get features
99 DomDocument doc
; // document being constructed
100 Node ctx
; // current context (parent node)
101 LinkedList entityCtx
; // entity context
102 List pending
; // namespace nodes waiting for a declaring element
113 // -- ContentHandler2 --
115 public void setDocumentLocator(Locator locator
)
117 this.locator
= locator
;
120 public void startDocument()
125 pending
= new LinkedList();
127 doc
= new DomDocument();
128 doc
.setStrictErrorChecking(false);
129 doc
.setBuilding(true);
132 final String FEATURES
= "http://xml.org/sax/features/";
133 final String PROPERTIES
= "http://xml.org/sax/properties/";
134 final String GNU_PROPERTIES
= "http://gnu.org/sax/properties/";
136 boolean standalone
= reader
.getFeature(FEATURES
+ "is-standalone");
137 doc
.setXmlStandalone(standalone
);
140 String version
= (String
) reader
.getProperty(PROPERTIES
+
141 "document-xml-version");
142 doc
.setXmlVersion(version
);
144 catch (SAXNotRecognizedException e
)
147 catch (SAXNotSupportedException e
)
150 if (locator
!= null && locator
instanceof Locator2
)
152 String encoding
= ((Locator2
) locator
).getEncoding();
153 doc
.setInputEncoding(encoding
);
157 String encoding
= (String
) reader
.getProperty(GNU_PROPERTIES
+
158 "document-xml-encoding");
159 doc
.setXmlEncoding(encoding
);
161 catch (SAXNotRecognizedException e
)
164 catch (SAXNotSupportedException e
)
169 public void endDocument()
172 doc
.setStrictErrorChecking(true);
173 doc
.setBuilding(false);
174 DomDoctype doctype
= (DomDoctype
) doc
.getDoctype();
177 doctype
.makeReadonly();
183 public void startPrefixMapping(String prefix
, String uri
)
188 String nsName
= (prefix
!= null && prefix
.length() > 0) ?
189 XMLNS_PREFIX
+ ":" + prefix
: XMLNS_PREFIX
;
190 DomAttr ns
= (DomAttr
) doc
.createAttributeNS(XMLNS_URI
, nsName
);
191 ns
.setNodeValue(uri
);
192 if (ctx
.getNodeType() == Node
.ATTRIBUTE_NODE
)
194 // Add to owner element
195 Node target
= ((Attr
) ctx
).getOwnerElement();
196 target
.getAttributes().setNamedItemNS(ns
);
200 // Add to pending list; namespace node will be inserted when
207 public void endPrefixMapping(String prefix
)
212 public void startElement(String uri
, String localName
, String qName
,
220 Element element
= createElement(uri
, localName
, qName
, atts
);
221 // add element to context
222 ctx
.appendChild(element
);
226 protected Element
createElement(String uri
, String localName
, String qName
,
230 // create element node
231 Element element
= namespaceAware ?
232 doc
.createElementNS(uri
, qName
) :
233 doc
.createElement(qName
);
234 NamedNodeMap attrs
= element
.getAttributes();
235 if (namespaceAware
&& !pending
.isEmpty())
237 // add pending namespace nodes
238 for (Iterator i
= pending
.iterator(); i
.hasNext(); )
240 Node ns
= (Node
) i
.next();
241 attrs
.setNamedItemNS(ns
);
246 int len
= atts
.getLength();
247 for (int i
= 0; i
< len
; i
++)
250 Attr attr
= createAttr(atts
, i
);
253 // add attribute to element
256 attrs
.setNamedItemNS(attr
);
260 attrs
.setNamedItem(attr
);
267 protected Attr
createAttr(Attributes atts
, int index
)
272 String a_uri
= atts
.getURI(index
);
273 String a_qName
= atts
.getQName(index
);
274 attr
= (DomAttr
) doc
.createAttributeNS(a_uri
, a_qName
);
278 String a_qName
= atts
.getQName(index
);
279 attr
= (DomAttr
) doc
.createAttribute(a_qName
);
281 attr
.setNodeValue(atts
.getValue(index
));
282 if (atts
instanceof Attributes2
)
284 Attributes2 atts2
= (Attributes2
) atts
;
285 // TODO attr.setDeclared(atts2.isDeclared(index));
286 attr
.setSpecified(atts2
.isSpecified(index
));
291 public void endElement(String uri
, String localName
, String qName
)
302 ctx
= ctx
.getParentNode();
305 public void characters(char[] c
, int off
, int len
)
308 if (interrupted
|| len
< 1)
312 ctx
.appendChild(createText(c
, off
, len
));
315 protected Text
createText(char[] c
, int off
, int len
)
318 Text text
= (inCDATA
&& !coalescing
) ?
319 doc
.createCDATASection(new String(c
, off
, len
)) :
320 doc
.createTextNode(new String(c
, off
, len
));
324 public void ignorableWhitespace(char[] c
, int off
, int len
)
331 if (!ignoreWhitespace
)
333 characters(c
, off
, len
);
337 public void processingInstruction(String target
, String data
)
344 Node pi
= createProcessingInstruction(target
, data
);
348 protected Node
createProcessingInstruction(String target
, String data
)
350 return doc
.createProcessingInstruction(target
, data
);
353 public void skippedEntity(String name
)
356 // This callback is totally pointless
359 // -- LexicalHandler --
361 public void startDTD(String name
, String publicId
, String systemId
)
368 Node doctype
= createDocumentType(name
, publicId
, systemId
);
369 doc
.appendChild(doctype
);
374 protected Node
createDocumentType(String name
, String publicId
,
377 return new DomDoctype(doc
, name
, publicId
, systemId
);
388 ctx
= ctx
.getParentNode();
391 public void startEntity(String name
)
396 DocumentType doctype
= doc
.getDoctype();
399 throw new SAXException("SAX parser error: " +
400 "reference to entity in undeclared doctype");
402 if ("[dtd]".equals(name
) || name
.charAt(0) == '%')
404 if (PREDEFINED_ENTITIES
.contains(name
))
407 NamedNodeMap entities
= doctype
.getEntities();
408 Entity entity
= (Entity
) entities
.getNamedItem(name
);
411 throw new SAXException("SAX parser error: " +
412 "reference to undeclared entity: " + name
);
414 EntityReference ref
= doc
.createEntityReference(name
);
415 // DomDocument populates with the entity replacement text, remove this
416 Node child
= ref
.getFirstChild();
417 while (child
!= null)
419 Node nextChild
= child
.getNextSibling();
420 ref
.removeChild(child
);
423 ctx
.appendChild(ref
);
427 public void endEntity(String name
)
432 if ("[dtd]".equals(name
) || name
.charAt(0) == '%')
434 if (PREDEFINED_ENTITIES
.contains(name
))
436 // Get entity reference
437 EntityReference ref
= (EntityReference
) ctx
;
438 if (!ref
.getNodeName().equals(name
))
439 throw new SAXException("expecting end of "+ref
.getNodeName()+" entity");
440 ctx
= ctx
.getParentNode();
441 if (ref
instanceof DomNode
)
442 ((DomNode
) ref
).makeReadonly();
443 if (expandEntityReferences
)
445 // Move entity content from reference node onto context
446 Node child
= ref
.getFirstChild();
447 while (child
!= null)
449 Node nextChild
= child
.getNextSibling();
450 ctx
.appendChild(child
);
453 ctx
.removeChild(ref
);
457 public void startCDATA()
463 public void endCDATA()
469 public void comment(char[] c
, int off
, int len
)
476 Node comment
= createComment(c
, off
, len
);
477 ctx
.appendChild(comment
);
480 protected Node
createComment(char[] c
, int off
, int len
)
482 return doc
.createComment(new String(c
, off
, len
));
487 public void notationDecl(String name
, String publicId
, String systemId
)
495 throw new SAXException("notation decl outside DTD");
496 DomDoctype doctype
= (DomDoctype
) ctx
;
497 doctype
.declareNotation(name
, publicId
, systemId
);
500 public void unparsedEntityDecl(String name
, String publicId
, String systemId
,
509 throw new SAXException("unparsed entity decl outside DTD");
510 DomDoctype doctype
= (DomDoctype
) ctx
;
511 Entity entity
= doctype
.declareEntity(name
, publicId
, systemId
,
517 public void elementDecl(String name
, String model
)
525 throw new SAXException("element decl outside DTD");
526 // Ignore fake element declarations generated by ValidationConsumer.
527 // If an element is not really declared in the DTD it will not be
528 // declared in the document model.
529 if (!(ctx
instanceof DomDoctype
))
533 DomDoctype doctype
= (DomDoctype
) ctx
;
534 doctype
.elementDecl(name
, model
);
537 public void attributeDecl(String eName
, String aName
, String type
,
538 String mode
, String value
)
546 throw new SAXException("attribute decl outside DTD");
547 DomDoctype doctype
= (DomDoctype
) ctx
;
548 doctype
.attributeDecl(eName
, aName
, type
, mode
, value
);
551 public void internalEntityDecl(String name
, String value
)
559 throw new SAXException("internal entity decl outside DTD");
560 DomDoctype doctype
= (DomDoctype
) ctx
;
561 Entity entity
= doctype
.declareEntity(name
, null, null, null);
564 Node text
= doc
.createTextNode(value
);
565 entity
.appendChild(text
);
569 public void externalEntityDecl(String name
, String publicId
, String systemId
)
577 throw new SAXException("external entity decl outside DTD");
578 DomDoctype doctype
= (DomDoctype
) ctx
;
579 Entity entity
= doctype
.declareEntity(name
, publicId
, systemId
, null);