KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > caucho > xml2 > DOMBuilder


1 /*
2  * Copyright (c) 1998-2006 Caucho Technology -- all rights reserved
3  *
4  * This file is part of Resin(R) Open Source
5  *
6  * Each copy or derived work must preserve the copyright notice and this
7  * notice unmodified.
8  *
9  * Resin Open Source is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * Resin Open Source is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
17  * of NON-INFRINGEMENT. See the GNU General Public License for more
18  * details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with Resin Open Source; if not, write to the
22  * Free SoftwareFoundation, Inc.
23  * 59 Temple Place, Suite 330
24  * Boston, MA 02111-1307 USA
25  *
26  * @author Scott Ferguson
27  */

28
29 package com.caucho.xml2;
30
31 import com.caucho.log.Log;
32 import com.caucho.util.CharBuffer;
33 import com.caucho.util.L10N;
34
35 import org.w3c.dom.*;
36 import org.xml.sax.Attributes JavaDoc;
37 import org.xml.sax.ContentHandler JavaDoc;
38 import org.xml.sax.ErrorHandler JavaDoc;
39 import org.xml.sax.Locator JavaDoc;
40 import org.xml.sax.SAXException JavaDoc;
41 import org.xml.sax.SAXParseException JavaDoc;
42
43 import javax.xml.namespace.QName JavaDoc;
44 import java.io.IOException JavaDoc;
45 import java.util.ArrayList JavaDoc;
46 import java.util.logging.Level JavaDoc;
47 import java.util.logging.Logger JavaDoc;
48
49 /**
50  * XMLWriter to create a DOM document.
51  */

52 public class DOMBuilder implements XMLWriter, ContentHandler JavaDoc, ErrorHandler JavaDoc {
53   static final Logger JavaDoc log = Log.open(DOMBuilder.class);
54   static final L10N L = new L10N(DOMBuilder.class);
55   static final String JavaDoc XMLNS = XmlParser.XMLNS;
56   
57   private QDocument _doc;
58   private Node _top;
59   private Node _node;
60
61   private String JavaDoc _singleText;
62   private CharBuffer _text = new CharBuffer();
63   
64   private boolean _escapeText;
65   private boolean _strictXml;
66
67   // If true, text and cdata sections should be combined.
68
private boolean _isCoalescing = true;
69   // If true, ignorable whitespace is skipped
70
private boolean _skipWhitespace = false;
71
72   private ArrayList JavaDoc<QName JavaDoc> _prefixNames = new ArrayList JavaDoc<QName JavaDoc>();
73   private ArrayList JavaDoc<String JavaDoc> _prefixValues = new ArrayList JavaDoc<String JavaDoc>();
74
75   private Locator JavaDoc _locator;
76   private ExtendedLocator _extLocator;
77   private String JavaDoc _systemId;
78
79   public DOMBuilder()
80   {
81   }
82
83   public void init(Node top)
84   {
85     if (top instanceof QDocument)
86       _doc = (QDocument) top;
87     else
88       _doc = (QDocument) top.getOwnerDocument();
89     _top = top;
90     _node = top;
91     
92     _singleText = null;
93
94     _prefixNames.clear();
95     _prefixValues.clear();
96   }
97
98   public void setSystemId(String JavaDoc systemId)
99   {
100     _systemId = systemId;
101     
102     if (systemId != null && _top instanceof Document) {
103       Document tdoc = (Document) _top;
104       DocumentType dtd = tdoc.getDoctype();
105       if (tdoc instanceof QDocument && dtd == null) {
106     dtd = new QDocumentType(null);
107     ((QDocument) tdoc).setDoctype(dtd);
108       }
109       
110       if (dtd instanceof QDocumentType && dtd.getSystemId() == null)
111         ((QDocumentType) dtd).setSystemId(systemId);
112     }
113
114     if (_doc != null)
115       _doc.setSystemId(systemId);
116   }
117
118   public String JavaDoc getSystemId()
119   {
120     return _systemId;
121   }
122
123   public void setFilename(String JavaDoc filename)
124   {
125     if (filename != null && _top instanceof QDocument) {
126       _doc.setRootFilename(filename);
127     }
128   }
129
130   /**
131    * Set true if we're only handling strict xml.
132    */

133   public void setStrictXML(boolean isStrictXml)
134   {
135     _strictXml = isStrictXml;
136   }
137
138   /**
139    * Set true if text and cdata nodes should be combined.
140    */

141   public void setCoalescing(boolean isCoalescing)
142   {
143     _isCoalescing = isCoalescing;
144   }
145
146   /**
147    * Set true if ignorable whitespace should be skipped.
148    */

149   public void setSkipWhitespace(boolean skipWhitespace)
150   {
151     _skipWhitespace = skipWhitespace;
152   }
153
154   public void setDocumentLocator(Locator JavaDoc loc)
155   {
156     if (_doc == null) {
157       _doc = new QDocument();
158       _node = _doc;
159       _top = _doc;
160     }
161
162     _locator = loc;
163     
164     if (loc instanceof ExtendedLocator)
165       _extLocator = (ExtendedLocator) loc;
166
167     if (_extLocator != null && _doc.getSystemId() == null)
168       _doc.setLocation(_extLocator.getSystemId(),
169                _extLocator.getFilename(),
170                _extLocator.getLineNumber(),
171                _extLocator.getColumnNumber());
172   }
173   
174   public void startPrefixMapping(String JavaDoc prefix, String JavaDoc url)
175   {
176     if (_node == null || _node == _top)
177       _doc.addNamespace(prefix, url);
178
179     if (prefix.equals("")) {
180       _prefixNames.add(new QName JavaDoc(null, "xmlns", XmlParser.XMLNS));
181       _prefixValues.add(url);
182     }
183     else {
184       _prefixNames.add(new QName JavaDoc("xmlns", prefix, XmlParser.XMLNS));
185       _prefixValues.add(url);
186     }
187   }
188   
189   public void endPrefixMapping(String JavaDoc prefix)
190   {
191   }
192
193   public Node getNode()
194   {
195     return _top;
196   }
197
198   public void startDocument()
199   {
200     if (_doc == null) {
201       _doc = new QDocument();
202       _node = _doc;
203       _top = _doc;
204     }
205   }
206
207   public void endDocument()
208     throws SAXException JavaDoc
209   {
210     popText();
211   }
212   
213   public void setLocation(String JavaDoc filename, int line, int column)
214   {
215   }
216
217   public void startElement(String JavaDoc uri, String JavaDoc localName, String JavaDoc qName)
218     throws IOException JavaDoc
219   {
220     popText();
221     
222     Element elt;
223
224     if (uri != null && ! uri.equals(""))
225       elt = _doc.createElementNS(uri, qName);
226     else if (! qName.equals(""))
227       elt = _doc.createElement(qName);
228     else
229       elt = _doc.createElement(localName);
230     
231     if (_node == _doc) {
232       if (_doc.getDocumentElement() == null)
233         ((QDocument) _doc).setDocumentElement(elt);
234     }
235     
236     _node.appendChild(elt);
237     _node = elt;
238
239     if (_extLocator != null && elt instanceof QElement) {
240       ((QElement) elt).setLocation(_extLocator.getSystemId(),
241                    _extLocator.getFilename(),
242                    _extLocator.getLineNumber(),
243                    _extLocator.getColumnNumber());
244     }
245   }
246
247   public void startElement(QName JavaDoc name, QAttributes attributes)
248     throws SAXException JavaDoc
249   {
250     popText();
251
252     QElement elt = (QElement) _doc.createElementByName(name);
253     _node.appendChild(elt);
254     _node = elt;
255     
256     if (_node == _doc) {
257       if (_doc.getDocumentElement() == null)
258         ((QDocument) _doc).setDocumentElement(elt);
259     }
260
261     for (int i = 0; i < _prefixNames.size(); i++) {
262       QName JavaDoc attrName = _prefixNames.get(i);
263       String JavaDoc value = _prefixValues.get(i);
264
265       elt.setAttribute(attrName, value);
266     }
267
268     _prefixNames.clear();
269     _prefixValues.clear();
270
271     int length = attributes.getLength();
272     for (int i = 0; i < length; i++) {
273       QName JavaDoc attrName = attributes.getName(i);
274       String JavaDoc value = attributes.getValue(i);
275
276       elt.setAttribute(attrName, value);
277     }
278
279     if (_extLocator != null) {
280       elt.setLocation(_extLocator.getSystemId(),
281               _extLocator.getFilename(),
282                       _extLocator.getLineNumber(),
283                       _extLocator.getColumnNumber());
284     }
285     
286     QDocumentType dtd = (QDocumentType) _doc.getDoctype();
287     if (dtd != null)
288       dtd.fillDefaults(elt);
289   }
290
291   public void startElement(String JavaDoc uri, String JavaDoc localName, String JavaDoc qName,
292                            Attributes JavaDoc attributes)
293     throws SAXException JavaDoc
294   {
295     popText();
296     
297     Element elt;
298
299     if (uri != null && ! uri.equals(""))
300       elt = _doc.createElementNS(uri, qName);
301     else if (! qName.equals(""))
302       elt = _doc.createElement(qName);
303     else
304       elt = _doc.createElement(localName);
305     
306     if (_node == _doc) {
307       if (_doc.getDocumentElement() == null)
308         ((QDocument) _doc).setDocumentElement(elt);
309       else if (_strictXml)
310         throw error(L.l("expected a single top-level element at `{0}'", qName));
311     }
312
313     _node.appendChild(elt);
314     _node = elt;
315
316     int length = attributes.getLength();
317     for (int i = 0; i < length; i++) {
318       String JavaDoc attrUri = attributes.getURI(i);
319       String JavaDoc attrQname = attributes.getQName(i);
320       String JavaDoc value = attributes.getValue(i);
321
322       Attr attr;
323
324       if (attrUri != null && ! attrUri.equals(""))
325         attr = _doc.createAttributeNS(attrUri, attrQname);
326       else if (! attrQname.equals(""))
327         attr = _doc.createAttribute(attrQname);
328       else
329         attr = _doc.createAttribute(attributes.getLocalName(i));
330       
331       attr.setNodeValue(value);
332
333       ((Element) _node).setAttributeNode(attr);
334     }
335
336     if (_extLocator != null)
337       ((QElement) elt).setLocation(_extLocator.getSystemId(),
338                    _extLocator.getFilename(),
339                    _extLocator.getLineNumber(),
340                    _extLocator.getColumnNumber());
341
342     QDocumentType dtd = (QDocumentType) _doc.getDoctype();
343     if (dtd != null) {
344       dtd.fillDefaults((QElement) elt);
345     }
346   }
347
348   public void dtd(QDocumentType dtd)
349   {
350     ((QDocument) _doc).setDoctype(dtd);
351     
352     ((QDocument) _doc).appendChild(dtd);
353   }
354
355   public void attribute(String JavaDoc uri, String JavaDoc localName, String JavaDoc qName,
356                         String JavaDoc value)
357     throws IOException JavaDoc
358   {
359     if (_node instanceof Element) {
360       Attr attr = _doc.createAttributeNS(uri, qName);
361       attr.setNodeValue(value);
362
363       ((Element) _node).setAttributeNode(attr);
364     }
365     else
366       ((QDocument) _node).setAttribute(qName, value);
367   }
368
369   public void endElement(String JavaDoc uri, String JavaDoc localName, String JavaDoc qName)
370   {
371     popText();
372
373     if (_node != null) // XXX:
374
_node = _node.getParentNode();
375     if (_node == null)
376       _node = _doc;
377   }
378
379   public void processingInstruction(String JavaDoc name, String JavaDoc data)
380   {
381     popText();
382     
383     ProcessingInstruction pi = _doc.createProcessingInstruction(name, data);
384
385     _node.appendChild(pi);
386   }
387
388   /**
389    * Handles the callback for a comment.
390    *
391    * @param data the content of the comment.
392    */

393   public void comment(char []buf, int offset, int length)
394     throws SAXException JavaDoc
395   {
396     try {
397       comment(new String JavaDoc(buf, offset, length));
398     } catch (IOException JavaDoc e) {
399       throw new SAXException JavaDoc(e);
400     }
401   }
402
403   /**
404    * Handles the callback for a comment.
405    *
406    * @param data the content of the comment.
407    */

408   public void comment(String JavaDoc data)
409     throws IOException JavaDoc
410   {
411     popText();
412     
413     Comment comment = _doc.createComment(data);
414
415     _node.appendChild(comment);
416   }
417
418   public boolean getEscapeText()
419   {
420     return _escapeText;
421   }
422
423   public void setEscapeText(boolean isEscaped)
424   {
425     _escapeText = isEscaped;
426   }
427
428   public void text(String JavaDoc text)
429     throws IOException JavaDoc
430   {
431     if (_singleText == null && _text.length() == 0) {
432       if (! text.equals(""))
433         _singleText = text;
434     }
435     else if (_singleText != null) {
436       _text.append(_singleText);
437       _text.append(text);
438     }
439     else
440       _text.append(text);
441     
442     if (! _isCoalescing)
443       popText();
444   }
445
446   public void text(char []buffer, int offset, int length)
447     throws IOException JavaDoc
448   {
449     if (length == 0)
450       return;
451     
452     if (_singleText != null) {
453       _singleText = null;
454       _text.append(_singleText);
455     }
456     _text.append(buffer, offset, length);
457     
458     if (! _isCoalescing)
459       popText();
460   }
461
462   /**
463    * Adds text characters to the current document.
464    */

465   public void characters(char []buffer, int offset, int length)
466     throws SAXException JavaDoc
467   {
468     if (length == 0)
469       return;
470     
471     if (_strictXml && _node == _doc) {
472       if (_doc.getDocumentElement() == null) {
473         while (length > 0 && XmlChar.isWhitespace(buffer[offset])) {
474           offset++;
475           length--;
476         }
477
478         for (int i = 0; i < length; i++) {
479           if (buffer[offset + i] == '\n' || buffer[offset + i] == '\r') {
480             length = i;
481             break;
482           }
483         }
484             
485         if (length > 16)
486           length = 16;
487
488         if (length > 0)
489           throw error(L.l("expected top element at `{0}'",
490                           new String JavaDoc(buffer, offset, length)));
491       }
492     }
493     
494     _text.append(buffer, offset, length);
495     
496     /*
497     if (! isCoalescing)
498       popText();
499     */

500   }
501
502   /**
503    * Handles the callback for ignorable whitespace.
504    *
505    * @param buffer the character buffer containing the whitespace.
506    * @param offset starting offset into the character buffer.
507    * @param length number of characters in the buffer.
508    */

509   public void ignorableWhitespace(char []buffer, int offset, int length)
510     throws SAXException JavaDoc
511   {
512     if (! _skipWhitespace)
513       characters(buffer, offset, length);
514   }
515
516   public void entityReference(String JavaDoc name)
517   {
518     popText();
519     
520     QEntityReference er = new QEntityReference(name);
521     er._owner = (QDocument) _doc;
522
523     _node.appendChild(er);
524   }
525
526   public void skippedEntity(String JavaDoc s)
527   {
528     _text.append(s);
529   }
530
531   public void cdata(String JavaDoc text)
532     throws IOException JavaDoc
533   {
534     popText();
535
536     _node.appendChild(_doc.createCDATASection(text));
537   }
538
539   public void cdata(char []buffer, int offset, int length)
540     throws IOException JavaDoc
541   {
542     cdata(new String JavaDoc(buffer, offset, length));
543   }
544
545   private void popText()
546   {
547     if (_singleText != null) {
548       Node text = _doc.createTextNode(_singleText);
549       _node.appendChild(text);
550
551       _singleText = null;
552       return;
553     }
554     
555     if (_text.length() == 0)
556       return;
557     
558     Node text = _doc.createTextNode(_text.toString());
559     _text.clear();
560
561     _node.appendChild(text);
562   }
563   
564   public void fatalError(SAXParseException JavaDoc e)
565     throws SAXException JavaDoc
566   {
567     log.log(Level.FINE, e.toString(), e);
568     
569     throw error(e.getMessage());
570   }
571
572   public void error(SAXParseException JavaDoc e)
573     throws SAXException JavaDoc
574   {
575     log.log(Level.FINER, e.toString(), e);
576     
577     throw error(e.getMessage());
578   }
579
580   public void warning(SAXParseException JavaDoc e)
581     throws SAXException JavaDoc
582   {
583     log.log(Level.FINER, e.toString(), e);
584   }
585     
586   /**
587    * Throws an appropriate error.
588    */

589   public SAXException JavaDoc createError(Exception JavaDoc e)
590   {
591     if (e instanceof SAXException JavaDoc)
592       return (SAXException JavaDoc) e;
593     else
594       return new SAXException JavaDoc(e);
595   }
596
597   /**
598    * Returns a new parse exception with filename and line if available.
599    */

600   XmlParseException error(String JavaDoc text)
601   {
602     if (_extLocator != null)
603       return new XmlParseException(_extLocator.getFilename() + ":" +
604                                    _extLocator.getLineNumber() + ": " + text);
605     else if (_locator != null)
606       return new XmlParseException(_locator.getSystemId() + ":" +
607                                    _locator.getLineNumber() + ": " + text);
608     else
609       return new XmlParseException(text);
610   }
611 }
612
Popular Tags