OSDN Git Service

Initial revision
[pf3gnuchains/gcc-fork.git] / libjava / classpath / gnu / xml / dom / ls / SAXEventSink.java
1 /* SAXEventSink.java -- 
2    Copyright (C) 1999,2000,2001 Free Software Foundation, Inc.
3
4 This file is part of GNU Classpath.
5
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.
10
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.
15
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.
20
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.
25
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. */
37
38 package gnu.xml.dom.ls;
39
40 import java.util.Iterator;
41 import java.util.LinkedList;
42 import java.util.List;
43 import javax.xml.XMLConstants;
44 import org.w3c.dom.Attr;
45 import org.w3c.dom.DocumentType;
46 import org.w3c.dom.Element;
47 import org.w3c.dom.Entity;
48 import org.w3c.dom.NamedNodeMap;
49 import org.w3c.dom.Node;
50 import org.w3c.dom.Text;
51 import org.xml.sax.Attributes;
52 import org.xml.sax.DTDHandler;
53 import org.xml.sax.Locator;
54 import org.xml.sax.SAXException;
55 import org.xml.sax.ext.Attributes2;
56 import org.xml.sax.ext.DeclHandler;
57 import org.xml.sax.ext.LexicalHandler;
58 import gnu.xml.aelfred2.ContentHandler2;
59 import gnu.xml.dom.DomAttr;
60 import gnu.xml.dom.DomDocument;
61 import gnu.xml.dom.DomDoctype;
62
63 /**
64  * A SAX content and lexical handler used to construct a DOM document.
65  *
66  * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
67  */
68 class SAXEventSink
69   implements ContentHandler2, LexicalHandler, DTDHandler, DeclHandler
70 {
71
72   private static final String XMLNS_URI = XMLConstants.XMLNS_ATTRIBUTE_NS_URI;
73   private static final String XMLNS_PREFIX = XMLConstants.XMLNS_ATTRIBUTE;
74
75   boolean namespaceAware;
76   boolean ignoreWhitespace;
77   boolean expandEntityReferences;
78   boolean ignoreComments;
79   boolean coalescing;
80   
81   DomDocument doc; // document being constructed
82   Node ctx; // current context (parent node)
83   LinkedList entityCtx; // entity context
84   List pending; // namespace nodes waiting for a declaring element
85   Locator locator;
86   boolean inCDATA;
87   boolean inDTD;
88   boolean interrupted;
89
90   void interrupt()
91   {
92     interrupted = true;
93   }
94
95   // -- ContentHandler2 --
96   
97   public void setDocumentLocator(Locator locator)
98   {
99     this.locator = locator;
100   }
101
102   public void startDocument()
103     throws SAXException
104   {
105     if (namespaceAware)
106       {
107         pending = new LinkedList();
108       }
109     doc = new DomDocument();
110     doc.setStrictErrorChecking(false);
111     doc.setBuilding(true);
112     ctx = doc;
113   }
114
115   public void xmlDecl(String version, String encoding, boolean standalone,
116                       String inputEncoding)
117     throws SAXException
118   {
119     if (interrupted)
120       {
121         return;
122       }
123     doc.setXmlVersion(version);
124     doc.setXmlEncoding(encoding);
125     doc.setXmlStandalone(standalone);
126     doc.setInputEncoding(inputEncoding);
127   }
128
129   public void endDocument()
130     throws SAXException
131   {
132     doc.setStrictErrorChecking(true);
133     doc.setBuilding(false);
134     DomDoctype doctype = (DomDoctype) doc.getDoctype();
135     if (doctype != null)
136       {
137         doctype.makeReadonly();
138       }
139     ctx = null;
140     locator = null;
141   }
142
143   public void startPrefixMapping(String prefix, String uri)
144     throws SAXException
145   {
146     if (namespaceAware)
147       {
148         String nsName = (prefix != null && prefix.length() > 0) ?
149           XMLNS_PREFIX + ":" + prefix : XMLNS_PREFIX;
150         DomAttr ns = (DomAttr) doc.createAttributeNS(XMLNS_URI, nsName);
151         ns.setNodeValue(uri);
152         if (ctx.getNodeType() == Node.ATTRIBUTE_NODE)
153           {
154             // Add to owner element
155             Node target = ((Attr) ctx).getOwnerElement();
156             target.getAttributes().setNamedItemNS(ns);
157           }
158         else
159           {
160             // Add to pending list; namespace node will be inserted when
161             // element is seen
162             pending.add(ns);
163           }
164       }
165   }
166
167   public void endPrefixMapping(String prefix)
168     throws SAXException
169   {
170   }
171
172   public void startElement(String uri, String localName, String qName,
173                            Attributes atts)
174     throws SAXException
175   {
176     if (interrupted)
177       {
178         return;
179       }
180     Element element = createElement(uri, localName, qName, atts);
181     // add element to context
182     ctx.appendChild(element);
183     ctx = element;
184   }
185
186   protected Element createElement(String uri, String localName, String qName,
187                                   Attributes atts)
188     throws SAXException
189   {
190     // create element node
191     Element element = namespaceAware ?
192       doc.createElementNS(uri, qName) :
193       doc.createElement(qName);
194     NamedNodeMap attrs = element.getAttributes();
195     if (namespaceAware && !pending.isEmpty())
196       {
197         // add pending namespace nodes
198         for (Iterator i = pending.iterator(); i.hasNext(); )
199           {
200             Node ns = (Node) i.next();
201             attrs.setNamedItemNS(ns);
202           }
203         pending.clear();
204       }
205     // add attributes
206     int len = atts.getLength();
207     for (int i = 0; i < len; i++)
208       {
209         // create attribute
210         Attr attr = createAttr(atts, i);
211         if (attr != null)
212           {
213             // add attribute to element
214             if (namespaceAware)
215               {
216                 attrs.setNamedItemNS(attr);
217               }
218             else
219               {
220                 attrs.setNamedItem(attr);
221               }
222           }
223       }
224     return element;
225   }
226
227   protected Attr createAttr(Attributes atts, int index)
228   {
229     DomAttr attr;
230     if (namespaceAware)
231       {
232         String a_uri = atts.getURI(index);
233         String a_qName = atts.getQName(index);
234         attr = (DomAttr) doc.createAttributeNS(a_uri, a_qName);
235       }
236     else
237       {
238         String a_qName = atts.getQName(index);
239         attr = (DomAttr) doc.createAttribute(a_qName);
240       }
241     attr.setNodeValue(atts.getValue(index));
242     if (atts instanceof Attributes2)
243       {
244         Attributes2 atts2 = (Attributes2) atts;
245         // TODO attr.setDeclared(atts2.isDeclared(index));
246         attr.setSpecified(atts2.isSpecified(index));
247       }
248     return attr;
249   }
250
251   public void endElement(String uri, String localName, String qName)
252     throws SAXException
253   {
254     if (interrupted)
255       {
256         return;
257       }
258     if (namespaceAware)
259       {
260         pending.clear();
261       }
262     ctx = ctx.getParentNode();
263   }
264
265   public void characters(char[] c, int off, int len)
266     throws SAXException
267   {
268     if (interrupted)
269       {
270         return;
271       }
272     ctx.appendChild(createText(c, off, len));
273   }
274
275   protected Text createText(char[] c, int off, int len)
276     throws SAXException
277   {
278     Text text = (inCDATA && !coalescing) ?
279       doc.createCDATASection(new String(c, off, len)) :
280       doc.createTextNode(new String(c, off, len));
281     return text;
282   }
283
284   public void ignorableWhitespace(char[] c, int off, int len)
285     throws SAXException
286   {
287     if (interrupted)
288       {
289         return;
290       }
291     if (!ignoreWhitespace)
292       {
293         characters(c, off, len);
294       }
295   }
296
297   public void processingInstruction(String target, String data)
298     throws SAXException
299   {
300     if (interrupted)
301       {
302         return;
303       }
304     if (!inDTD)
305       {
306         Node pi = createProcessingInstruction(target, data);
307         ctx.appendChild(pi);
308       }
309   }
310
311   protected Node createProcessingInstruction(String target, String data)
312   {
313     return doc.createProcessingInstruction(target, data);
314   }
315
316   public void skippedEntity(String name)
317     throws SAXException
318   {
319     // This callback is totally pointless
320   }
321
322   // -- LexicalHandler --
323   
324   public void startDTD(String name, String publicId, String systemId)
325     throws SAXException
326   {
327     if (interrupted)
328       {
329         return;
330       }
331     Node doctype = createDocumentType(name, publicId, systemId);
332     doc.appendChild(doctype);
333     ctx = doctype;
334     inDTD = true;
335   }
336
337   protected Node createDocumentType(String name, String publicId,
338                                     String systemId)
339   {
340     return new DomDoctype(doc, name, publicId, systemId);
341   }
342
343   public void endDTD()
344     throws SAXException
345   {
346     if (interrupted)
347       {
348         return;
349       }
350     inDTD = false;
351     ctx = ctx.getParentNode();
352   }
353
354   public void startEntity(String name)
355     throws SAXException
356   {
357     DocumentType doctype = doc.getDoctype();
358     if (doctype == null)
359       {
360         throw new SAXException("SAX parser error: " +
361                                "reference to entity in undeclared doctype");
362       }
363     if ("[dtd]".equals(name) || name.charAt(0) == '%')
364       {
365         // Ignore DTD and parameter entities
366         ctx = doctype;
367         return;
368       }
369     if ("lt".equals(name) ||
370         "gt".equals(name) ||
371         "amp".equals(name) ||
372         "apos".equals(name) ||
373         "quot".equals(name))
374       {
375         return;
376       }
377     // Get entity
378     NamedNodeMap entities = doctype.getEntities();
379     Entity entity = (Entity) entities.getNamedItem(name);
380     if (entity == null)
381       {
382         throw new SAXException("SAX parser error: " +
383                                "reference to undeclared entity: " + name);
384       }
385     pushEntity(entity);
386   }
387
388   public void endEntity(String name)
389     throws SAXException
390   {
391     if ("[dtd]".equals(name) || name.charAt(0) == '%')
392       {
393         // Ignore DTD and parameter entities
394         return;
395       }
396     if ("lt".equals(name) ||
397         "gt".equals(name) ||
398         "amp".equals(name) ||
399         "apos".equals(name) ||
400         "quot".equals(name))
401       {
402         return;
403       }
404     // Get entity
405     Entity entity = popEntity();
406     // TODO resolve external entities to ensure that entity has content
407     if (expandEntityReferences)
408       {
409         // Get entity content
410         for (Node child = entity.getFirstChild(); child != null;
411              child = child.getNextSibling())
412           {
413             ctx.appendChild(child);
414           }
415       }
416     else
417       {
418         Node entityReference = doc.createEntityReference(name);
419         ctx.appendChild(entityReference);
420       }
421   }
422
423   void pushEntity(Node entity)
424   {
425     if (entityCtx == null)
426       {
427         entityCtx = new LinkedList();
428       }
429     entityCtx.addLast(ctx);
430     ctx = entity;
431   }
432
433   Entity popEntity()
434   {
435     Entity ret = (Entity) ctx;
436     ctx = (Node) entityCtx.removeLast();
437     return ret;
438   }
439
440   public void startCDATA()
441     throws SAXException
442   {
443     inCDATA = true;
444   }
445
446   public void endCDATA()
447     throws SAXException
448   {
449     inCDATA = false;
450   }
451
452   public void comment(char[] c, int off, int len)
453     throws SAXException
454   {
455     if (interrupted)
456       {
457         return;
458       }
459     if (!inDTD)
460       {
461         Node comment = createComment(c, off, len);
462         ctx.appendChild(comment);
463       }
464   }
465
466   protected Node createComment(char[] c, int off, int len)
467   {
468     return doc.createComment(new String(c, off, len));
469   }
470
471   // -- DTDHandler --
472
473   public void notationDecl(String name, String publicId, String systemId)
474     throws SAXException
475   {
476     if (interrupted)
477       {
478         return;
479       }
480     DomDoctype doctype = (DomDoctype) ctx;
481     doctype.declareNotation(name, publicId, systemId);
482   }
483
484   public void unparsedEntityDecl(String name, String publicId, String systemId,
485                                  String notationName)
486     throws SAXException
487   {
488     if (interrupted)
489       {
490         return;
491       }
492     DomDoctype doctype = (DomDoctype) ctx;
493     Entity entity = doctype.declareEntity(name, publicId, systemId,
494                                           notationName);
495   }
496
497   // -- DeclHandler --
498   
499   public void elementDecl(String name, String model)
500     throws SAXException
501   {
502     if (interrupted)
503       {
504         return;
505       }
506     // Ignore fake element declarations generated by ValidationConsumer.
507     // If an element is not really declared in the DTD it will not be
508     // declared in the document model.
509     if (!(ctx instanceof DomDoctype))
510       {
511         return;
512       }
513     DomDoctype doctype = (DomDoctype) ctx;
514     doctype.elementDecl(name, model);
515   }
516
517   public void attributeDecl(String eName, String aName, String type,
518                             String mode, String value)
519     throws SAXException
520   {
521     if (interrupted)
522       {
523         return;
524       }
525     DomDoctype doctype = (DomDoctype) ctx;
526     doctype.attributeDecl(eName, aName, type, mode, value);
527   }
528
529   public void internalEntityDecl(String name, String value)
530     throws SAXException
531   {
532     if (interrupted)
533       {
534         return;
535       }
536     DomDoctype doctype = (DomDoctype) ctx;
537     Entity entity = doctype.declareEntity(name, null, null, null);
538     if (entity != null)
539       {
540         Node text = doc.createTextNode(value);
541         entity.appendChild(text);
542       }
543   }
544
545   public void externalEntityDecl(String name, String publicId, String systemId)
546     throws SAXException
547   {
548     if (interrupted)
549       {
550         return;
551       }
552     DomDoctype doctype = (DomDoctype) ctx;
553     Entity entity = doctype.declareEntity(name, publicId, systemId, null);
554   }
555   
556 }
557