KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > enhydra > xml > xmlc > parsers > DocBuilder


1 /*
2  * Enhydra Java Application Server Project
3  *
4  * The contents of this file are subject to the Enhydra Public License
5  * Version 1.1 (the "License"); you may not use this file except in
6  * compliance with the License. You may obtain a copy of the License on
7  * the Enhydra web site ( http://www.enhydra.org/ ).
8  *
9  * Software distributed under the License is distributed on an "AS IS"
10  * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
11  * the License for the specific terms governing rights and limitations
12  * under the License.
13  *
14  * The Initial Developer of the Enhydra Application Server is Lutris
15  * Technologies, Inc. The Enhydra Application Server and portions created
16  * by Lutris Technologies, Inc. are Copyright Lutris Technologies, Inc.
17  * All Rights Reserved.
18  *
19  * Contributor(s):
20  *
21  * $Id: DocBuilder.java,v 1.2 2005/01/26 08:29:24 jkjome Exp $
22  */

23
24 package org.enhydra.xml.xmlc.parsers;
25
26 import java.util.ArrayList JavaDoc;
27
28 import org.enhydra.xml.xmlc.XMLCError;
29 import org.enhydra.xml.xmlc.XMLCException;
30 import org.enhydra.xml.xmlc.dom.XMLCDocument;
31 import org.enhydra.xml.xmlc.dom.XMLCDomFactory;
32 import org.w3c.dom.Document JavaDoc;
33 import org.w3c.dom.Element JavaDoc;
34 import org.w3c.dom.EntityReference JavaDoc;
35 import org.w3c.dom.Node JavaDoc;
36
37 /**
38  * Class for building a Document DOM. Used by XMLC XML parsers to build a DOM
39  * as well as collect other information about the document.
40  * <P>
41  * The document builder functions assume they are being called in the order the
42  * document is parsed. They keep a current node where new child nodes are
43  * appended.
44  */

45 public class DocBuilder {
46     /**
47      * Default XML encoding.
48      */

49     private static final String JavaDoc DEFAULT_XML_ENCODING = "UTF-8";
50
51     /**
52      * Factory for creating the document.
53      */

54     private XMLCDomFactory fDomFactory;
55
56     /**
57      * XMLC container for document.
58      */

59     private XMLCDocument fXmlcDoc;
60
61     /**
62      * The document.
63      */

64     private Document fDocument;
65
66     /**
67      * Information from the DocumentType.
68      */

69     private String JavaDoc fDocTypeName; // Root element.
70
private String JavaDoc fPublicId;
71     private String JavaDoc fSystemId;
72
73     /*
74      * Internal subset as a string.
75      */

76     private String JavaDoc fInternalSubsetStr;
77
78     /**
79      * The current node that is being constructed. This functions
80      * as a stack during document construction.
81      */

82     protected Node JavaDoc fCurrentNode;
83
84     /**
85      * Holds comments and processing instructions before the first element
86      * until the first element is encountered. Comments are strings,
87      * processing instructions are string arrays of length two.
88      */

89     private ArrayList JavaDoc fPendingPreDocument;
90
91     /**
92      * Constructor.
93      *
94      * @param domFactory Factory class for Documents.
95      */

96     public DocBuilder(XMLCDomFactory domFactory) throws XMLCException {
97         fDomFactory = domFactory;
98         fXmlcDoc = new XMLCDocument(domFactory);
99     }
100
101     /**
102      * Generate an error if the doc type has been created, indicating
103      * a bug in the code using this class.
104      */

105     private void checkIfAlreadyCreated() {
106         if (fDocument != null) {
107             throw new XMLCError("XMLC bug: attempt to add document type data after DocumentType object has been created");
108         }
109     }
110
111     /**
112      * Set the XML version.
113      *
114      * @param xmlVersion XML version string.
115      */

116     public void setXMLVersion(String JavaDoc xmlVersion) {
117         fXmlcDoc.setXMLVersion(xmlVersion);
118     }
119
120     /**
121      * Set the encoding for the document.
122      *
123      * @param encoding The encoding for the document.
124      */

125     public void setEncoding(String JavaDoc encoding) {
126         fXmlcDoc.setEncoding(encoding);
127     }
128
129     /**
130      * Set the document type name (rootElement).
131      *
132      * @param docTypeName The Document type name (also root node name).
133      */

134     public void setDocumentTypeName(String JavaDoc docTypeName) {
135         checkIfAlreadyCreated();
136         fDocTypeName = docTypeName;
137     }
138     
139     /**
140      * Set the publicId.
141      *
142      * @param publicId Document type public id or null if standalone.
143      */

144     public void setPublicId(String JavaDoc publicId) {
145         checkIfAlreadyCreated();
146         fPublicId = publicId;
147     }
148
149     /**
150      * Set the systemId.
151      *
152      * @param systemId Document type system id or null if standalone.
153      */

154     public void setSystemId(String JavaDoc systemId) {
155         checkIfAlreadyCreated();
156         fSystemId = systemId;
157     }
158
159     /**
160      * Add internal subset as a single string.
161      */

162     public void setInternalSubset(String JavaDoc subsetStr) {
163         checkIfAlreadyCreated();
164         fInternalSubsetStr = subsetStr;
165     }
166
167     /**
168      * Flag a element as having #PCDATA as part of its content model.
169      */

170     public void addPCDataContentElement(String JavaDoc elementName) {
171         checkIfAlreadyCreated();
172         fXmlcDoc.addPCDataContentElement(elementName);
173     }
174
175     /**
176      * Define an element id attribute.
177      */

178     public void addIdAttribute(String JavaDoc elementName,
179                                String JavaDoc attributeName) {
180         checkIfAlreadyCreated();
181         fXmlcDoc.addIdAttribute(elementName, attributeName);
182     }
183
184     /**
185      * Generate error about a method being called that should be called before
186      * the document is created.
187      */

188     private void docNotCreatedError() {
189         throw new XMLCError("Bug: parser event on document contents occured before document is created");
190     }
191
192     /**
193      * Hold a comment until the start of the document.
194      */

195     private void holdComment(String JavaDoc data) {
196         if (fPendingPreDocument == null) {
197             fPendingPreDocument = new ArrayList JavaDoc();
198         }
199         fPendingPreDocument.add(data);
200     }
201
202     /**
203      * Hold a processing instruction until the start of the document.
204      */

205     private void holdProcessingInstruction(String JavaDoc target,
206                                            String JavaDoc data) {
207         if (fPendingPreDocument == null) {
208             fPendingPreDocument = new ArrayList JavaDoc();
209         }
210         fPendingPreDocument.add(new String JavaDoc[]{target, data});
211     }
212
213     /**
214      * Add in comments and processing instructions that occured before the
215      * first element.
216      */

217     private void addPendingPreDocument() {
218         // Add comments before document element.
219
Node JavaDoc first = fDocument.getFirstChild();
220         for (int idx = 0; idx < fPendingPreDocument.size(); idx++) {
221             Object JavaDoc entry = fPendingPreDocument.get(idx);
222             if (entry instanceof String JavaDoc) {
223                 fDocument.insertBefore(fDocument.createComment((String JavaDoc)entry),
224                                        first);
225             } else {
226                 String JavaDoc[] pi = (String JavaDoc[])entry;
227                 fDocument.insertBefore(fDocument.createProcessingInstruction(pi[0], pi[1]),
228                                        first);
229             }
230         }
231     }
232
233     /**
234      * Create the Document object when the first element of the document is
235      * found. This is delayed until the the first element, since all
236      * information needed to build the document is not available until that
237      * time.
238      */

239     private void createDocument(String JavaDoc namespaceURI,
240                                 String JavaDoc rootTagName) {
241         if ((fPublicId != null) || (fSystemId != null) || (fInternalSubsetStr != null)) {
242             fXmlcDoc.createDocumentType(fDocTypeName, fPublicId, fSystemId,
243                                         fInternalSubsetStr);
244         }
245         fDocument = fXmlcDoc.createDocument(namespaceURI, rootTagName);
246
247         fCurrentNode = fDocument.getDocumentElement();
248         if (fPendingPreDocument != null) {
249             addPendingPreDocument();
250         }
251     }
252
253     /**
254      * Get the document associated with this object.
255      */

256     public XMLCDocument getDocument() {
257         if (fDocument == null) {
258             throw new XMLCError("XMLC bug: Attempt to get document that hasn;t been created");
259         }
260         return fXmlcDoc;
261     }
262
263     /**
264      * Get the node on the top of the stack during parsing.
265      * FIXME: To support the broken swing parser.
266      */

267     public Node JavaDoc getCurrentNode() {
268         return fCurrentNode;
269     }
270
271     /**
272      * Pop the current node off of the stack. This is *only* used
273      * during error recover from a broken parser.
274      * FIXME: This and getCurrentNode() should go away when the
275      * with the broken swing parser.
276      */

277     public void popCurrentNode() {
278         fCurrentNode = fCurrentNode.getParentNode();
279     }
280
281     /**
282      * Start a new Element.
283      */

284     public void startElement(String JavaDoc namespaceURI,
285                              String JavaDoc tagName) {
286         if (fDocument == null) {
287             // root (first) element
288
createDocument(namespaceURI, tagName);
289         } else {
290             // non-root element
291
Element JavaDoc element;
292             if (namespaceURI != null) {
293                 element = fDocument.createElementNS(namespaceURI, tagName);
294             } else {
295                 element = fDocument.createElement(tagName);
296             }
297             fCurrentNode.appendChild(element);
298             fCurrentNode = element;
299         }
300     }
301     
302     /**
303      * Add an attribute to the element on the top of the
304      * stack.
305      */

306     //FIXME: This doesn't handle attr entity refs
307
public void addAttribute(String JavaDoc namespaceURI,
308                              String JavaDoc name,
309                              String JavaDoc value) {
310         // Xerces code sezs: DOM Level 2 wants all namespace declaration
311
// attributes to be bound to "http://www.w3.org/2000/xmlns/" So as
312
// long as the XML parser doesn't do it, it needs to done here.
313
if ((namespaceURI == null) || (namespaceURI.length() == 0)) {
314             int prefixIdx = name.indexOf(':');
315             String JavaDoc prefix = (prefixIdx < 0) ? null : name.substring(0, prefixIdx);
316             if ((prefix != null) && (prefix.equals("xmlns"))
317                 || (name.equals("xmlns"))) {
318                 namespaceURI = "http://www.w3.org/2000/xmlns/";
319             }
320         }
321         if (namespaceURI != null) {
322             ((Element JavaDoc)fCurrentNode).setAttributeNS(namespaceURI, name, value);
323         } else {
324             ((Element JavaDoc)fCurrentNode).setAttribute(name, value);
325         }
326     }
327
328     /**
329      * Finish the element being constructed.
330      */

331     public void finishElement() {
332         if (fCurrentNode == null) {
333             throw new XMLCError("node stack underflow; malformed document");
334         }
335         if (!(fCurrentNode instanceof Element JavaDoc)) {
336             throw new XMLCError("DOM node top of stack not a element for end tag");
337         }
338         fCurrentNode = fCurrentNode.getParentNode();
339     }
340
341     /**
342      * Start an entity reference in the document (not DTD).
343      */

344     public void startEntityReference(String JavaDoc entityName) {
345         if (fDocument == null) {
346             docNotCreatedError();
347         }
348
349         EntityReference JavaDoc entityRef = fDocument.createEntityReference(entityName);
350         fCurrentNode.appendChild(entityRef);
351         fCurrentNode = entityRef;
352     }
353
354     /**
355      * End an entity reference.
356      */

357     public void endEntityReference() {
358         if (fCurrentNode == null) {
359             throw new XMLCError("node stack underflow; malformed document");
360         }
361         if (!(fCurrentNode instanceof EntityReference JavaDoc)) {
362             throw new XMLCError("DOM node top of stack not a EntityReference for end tag");
363         }
364         fCurrentNode = fCurrentNode.getParentNode();
365     }
366
367     
368     /**
369      * Add a <code>Text</code> node.
370      */

371     public void addTextNode(String JavaDoc data) {
372         if (fDocument == null) {
373             docNotCreatedError();
374         }
375         fCurrentNode.appendChild(fDocument.createTextNode(data));
376     }
377
378     /**
379      * Add a <code>Comment</code> node.
380      */

381     public void addComment(String JavaDoc data) {
382         if (fDocument == null) {
383             holdComment(data); // before first element..
384
} else {
385             fCurrentNode.appendChild(fDocument.createComment(data));
386         }
387     }
388
389     /**
390      * Add a <code>CDATASection</code> node.
391      */

392     public void addCDATASection(String JavaDoc data) {
393         if (fDocument == null) {
394             docNotCreatedError();
395         }
396         fCurrentNode.appendChild(fDocument.createCDATASection(data));
397     }
398
399     /**
400      * Add a <code>ProcessingInstruction</code> node.
401      */

402     public void addProcessingInstruction(String JavaDoc target,
403                                          String JavaDoc data) {
404         if (fDocument == null) {
405             holdProcessingInstruction(target, data);
406         } else {
407             fCurrentNode.appendChild(fDocument.createProcessingInstruction(target, data));
408         }
409     }
410
411     /**
412      * Add an EntityReference object.
413      */

414     public void addEntityReference(String JavaDoc name) {
415         if (fDocument == null) {
416             docNotCreatedError();
417         }
418         fCurrentNode.appendChild(fDocument.createEntityReference(name));
419     }
420
421     /**
422      * Called at the end of parsing, to finish any pending tasks, default
423      * values, etc.
424      */

425     public void finish() {
426         if (fXmlcDoc.getEncoding() == null) {
427             fXmlcDoc.setEncoding(DEFAULT_XML_ENCODING);
428         }
429     }
430 }
431
Popular Tags