KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > xml > utils > DOMBuilder


1 /*
2  * Copyright 1999-2004 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16 /*
17  * $Id: DOMBuilder.java,v 1.19 2004/02/25 13:07:51 aruny Exp $
18  */

19 package org.apache.xml.utils;
20
21 import java.util.Stack JavaDoc;
22
23 import org.apache.xml.res.XMLErrorResources;
24 import org.apache.xml.res.XMLMessages;
25
26 import org.w3c.dom.Document JavaDoc;
27 import org.w3c.dom.DocumentFragment JavaDoc;
28 import org.w3c.dom.Element JavaDoc;
29 import org.w3c.dom.Node JavaDoc;
30 import org.w3c.dom.Text JavaDoc;
31 import org.w3c.dom.CDATASection JavaDoc;
32
33 import org.xml.sax.Attributes JavaDoc;
34 import org.xml.sax.ContentHandler JavaDoc;
35 import org.xml.sax.Locator JavaDoc;
36 import org.xml.sax.ext.LexicalHandler JavaDoc;
37 /**
38  * This class takes SAX events (in addition to some extra events
39  * that SAX doesn't handle yet) and adds the result to a document
40  * or document fragment.
41  * @xsl.usage general
42  */

43 public class DOMBuilder
44         implements ContentHandler JavaDoc, LexicalHandler JavaDoc
45 {
46
47   /** Root document */
48   public Document JavaDoc m_doc;
49
50   /** Current node */
51   protected Node JavaDoc m_currentNode = null;
52
53   /** First node of document fragment or null if not a DocumentFragment */
54   public DocumentFragment JavaDoc m_docFrag = null;
55
56   /** Vector of element nodes */
57   protected Stack JavaDoc m_elemStack = new Stack JavaDoc();
58
59   /**
60    * DOMBuilder instance constructor... it will add the DOM nodes
61    * to the document fragment.
62    *
63    * @param doc Root document
64    * @param node Current node
65    */

66   public DOMBuilder(Document JavaDoc doc, Node JavaDoc node)
67   {
68     m_doc = doc;
69     m_currentNode = node;
70   }
71
72   /**
73    * DOMBuilder instance constructor... it will add the DOM nodes
74    * to the document fragment.
75    *
76    * @param doc Root document
77    * @param docFrag Document fragment
78    */

79   public DOMBuilder(Document JavaDoc doc, DocumentFragment JavaDoc docFrag)
80   {
81     m_doc = doc;
82     m_docFrag = docFrag;
83   }
84
85   /**
86    * DOMBuilder instance constructor... it will add the DOM nodes
87    * to the document.
88    *
89    * @param doc Root document
90    */

91   public DOMBuilder(Document JavaDoc doc)
92   {
93     m_doc = doc;
94   }
95
96   /**
97    * Get the root node of the DOM being created. This
98    * is either a Document or a DocumentFragment.
99    *
100    * @return The root document or document fragment if not null
101    */

102   public Node JavaDoc getRootNode()
103   {
104     return (null != m_docFrag) ? (Node JavaDoc) m_docFrag : (Node JavaDoc) m_doc;
105   }
106
107   /**
108    * Get the node currently being processed.
109    *
110    * @return the current node being processed
111    */

112   public Node JavaDoc getCurrentNode()
113   {
114     return m_currentNode;
115   }
116
117   /**
118    * Return null since there is no Writer for this class.
119    *
120    * @return null
121    */

122   public java.io.Writer JavaDoc getWriter()
123   {
124     return null;
125   }
126
127   /**
128    * Append a node to the current container.
129    *
130    * @param newNode New node to append
131    */

132   protected void append(Node JavaDoc newNode) throws org.xml.sax.SAXException JavaDoc
133   {
134
135     Node JavaDoc currentNode = m_currentNode;
136
137     if (null != currentNode)
138     {
139       currentNode.appendChild(newNode);
140
141       // System.out.println(newNode.getNodeName());
142
}
143     else if (null != m_docFrag)
144     {
145       m_docFrag.appendChild(newNode);
146     }
147     else
148     {
149       boolean ok = true;
150       short type = newNode.getNodeType();
151
152       if (type == Node.TEXT_NODE)
153       {
154         String JavaDoc data = newNode.getNodeValue();
155
156         if ((null != data) && (data.trim().length() > 0))
157         {
158           throw new org.xml.sax.SAXException JavaDoc(
159             XMLMessages.createXMLMessage(
160               XMLErrorResources.ER_CANT_OUTPUT_TEXT_BEFORE_DOC, null)); //"Warning: can't output text before document element! Ignoring...");
161
}
162
163         ok = false;
164       }
165       else if (type == Node.ELEMENT_NODE)
166       {
167         if (m_doc.getDocumentElement() != null)
168         {
169           throw new org.xml.sax.SAXException JavaDoc(
170             XMLMessages.createXMLMessage(
171               XMLErrorResources.ER_CANT_HAVE_MORE_THAN_ONE_ROOT, null)); //"Can't have more than one root on a DOM!");
172
}
173       }
174
175       if (ok)
176         m_doc.appendChild(newNode);
177     }
178   }
179
180   /**
181    * Receive an object for locating the origin of SAX document events.
182    *
183    * <p>SAX parsers are strongly encouraged (though not absolutely
184    * required) to supply a locator: if it does so, it must supply
185    * the locator to the application by invoking this method before
186    * invoking any of the other methods in the ContentHandler
187    * interface.</p>
188    *
189    * <p>The locator allows the application to determine the end
190    * position of any document-related event, even if the parser is
191    * not reporting an error. Typically, the application will
192    * use this information for reporting its own errors (such as
193    * character content that does not match an application's
194    * business rules). The information returned by the locator
195    * is probably not sufficient for use with a search engine.</p>
196    *
197    * <p>Note that the locator will return correct information only
198    * during the invocation of the events in this interface. The
199    * application should not attempt to use it at any other time.</p>
200    *
201    * @param locator An object that can return the location of
202    * any SAX document event.
203    * @see org.xml.sax.Locator
204    */

205   public void setDocumentLocator(Locator JavaDoc locator)
206   {
207
208     // No action for the moment.
209
}
210
211   /**
212    * Receive notification of the beginning of a document.
213    *
214    * <p>The SAX parser will invoke this method only once, before any
215    * other methods in this interface or in DTDHandler (except for
216    * setDocumentLocator).</p>
217    */

218   public void startDocument() throws org.xml.sax.SAXException JavaDoc
219   {
220
221     // No action for the moment.
222
}
223
224   /**
225    * Receive notification of the end of a document.
226    *
227    * <p>The SAX parser will invoke this method only once, and it will
228    * be the last method invoked during the parse. The parser shall
229    * not invoke this method until it has either abandoned parsing
230    * (because of an unrecoverable error) or reached the end of
231    * input.</p>
232    */

233   public void endDocument() throws org.xml.sax.SAXException JavaDoc
234   {
235
236     // No action for the moment.
237
}
238
239   /**
240    * Receive notification of the beginning of an element.
241    *
242    * <p>The Parser will invoke this method at the beginning of every
243    * element in the XML document; there will be a corresponding
244    * endElement() event for every startElement() event (even when the
245    * element is empty). All of the element's content will be
246    * reported, in order, before the corresponding endElement()
247    * event.</p>
248    *
249    * <p>If the element name has a namespace prefix, the prefix will
250    * still be attached. Note that the attribute list provided will
251    * contain only attributes with explicit values (specified or
252    * defaulted): #IMPLIED attributes will be omitted.</p>
253    *
254    *
255    * @param ns The namespace of the node
256    * @param localName The local part of the qualified name
257    * @param name The element name.
258    * @param atts The attributes attached to the element, if any.
259    * @see #endElement
260    * @see org.xml.sax.Attributes
261    */

262   public void startElement(
263           String JavaDoc ns, String JavaDoc localName, String JavaDoc name, Attributes JavaDoc atts)
264             throws org.xml.sax.SAXException JavaDoc
265   {
266
267     Element JavaDoc elem;
268
269     // Note that the namespace-aware call must be used to correctly
270
// construct a Level 2 DOM, even for non-namespaced nodes.
271
if ((null == ns) || (ns.length() == 0))
272       elem = m_doc.createElementNS(null,name);
273     else
274       elem = m_doc.createElementNS(ns, name);
275
276     append(elem);
277
278     try
279     {
280       int nAtts = atts.getLength();
281
282       if (0 != nAtts)
283       {
284         for (int i = 0; i < nAtts; i++)
285         {
286
287           //System.out.println("type " + atts.getType(i) + " name " + atts.getLocalName(i) );
288
// First handle a possible ID attribute
289
if (atts.getType(i).equalsIgnoreCase("ID"))
290             setIDAttribute(atts.getValue(i), elem);
291
292           String JavaDoc attrNS = atts.getURI(i);
293
294           if("".equals(attrNS))
295             attrNS = null; // DOM represents no-namespace as null
296

297           // System.out.println("attrNS: "+attrNS+", localName: "+atts.getQName(i)
298
// +", qname: "+atts.getQName(i)+", value: "+atts.getValue(i));
299
// Crimson won't let us set an xmlns: attribute on the DOM.
300
String JavaDoc attrQName = atts.getQName(i);
301
302           // In SAX, xmlns: attributes have an empty namespace, while in DOM they should have the xmlns namespace
303
if (attrQName.startsWith("xmlns:"))
304             attrNS = "http://www.w3.org/2000/xmlns/";
305
306           // ALWAYS use the DOM Level 2 call!
307
elem.setAttributeNS(attrNS,attrQName, atts.getValue(i));
308         }
309       }
310
311       // append(elem);
312

313       m_elemStack.push(elem);
314
315       m_currentNode = elem;
316
317       // append(elem);
318
}
319     catch(java.lang.Exception JavaDoc de)
320     {
321       // de.printStackTrace();
322
throw new org.xml.sax.SAXException JavaDoc(de);
323     }
324
325   }
326
327   /**
328
329
330
331    * Receive notification of the end of an element.
332    *
333    * <p>The SAX parser will invoke this method at the end of every
334    * element in the XML document; there will be a corresponding
335    * startElement() event for every endElement() event (even when the
336    * element is empty).</p>
337    *
338    * <p>If the element name has a namespace prefix, the prefix will
339    * still be attached to the name.</p>
340    *
341    *
342    * @param ns the namespace of the element
343    * @param localName The local part of the qualified name of the element
344    * @param name The element name
345    */

346   public void endElement(String JavaDoc ns, String JavaDoc localName, String JavaDoc name)
347           throws org.xml.sax.SAXException JavaDoc
348   {
349     m_elemStack.pop();
350     m_currentNode = m_elemStack.isEmpty() ? null : (Node JavaDoc)m_elemStack.peek();
351   }
352
353   /**
354    * Set an ID string to node association in the ID table.
355    *
356    * @param id The ID string.
357    * @param elem The associated ID.
358    */

359   public void setIDAttribute(String JavaDoc id, Element JavaDoc elem)
360   {
361
362     // Do nothing. This method is meant to be overiden.
363
}
364
365   /**
366    * Receive notification of character data.
367    *
368    * <p>The Parser will call this method to report