KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > tomcat > util > digester > NodeCreateRule


1 /* $Id: NodeCreateRule.java 467222 2006-10-24 03:17:11Z markt $
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one or more
4  * contributor license agreements. See the NOTICE file distributed with
5  * this work for additional information regarding copyright ownership.
6  * The ASF licenses this file to You under the Apache License, Version 2.0
7  * (the "License"); you may not use this file except in compliance with
8  * the License. You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */

18
19
20 package org.apache.tomcat.util.digester;
21
22
23 import javax.xml.parsers.DocumentBuilder JavaDoc;
24 import javax.xml.parsers.DocumentBuilderFactory JavaDoc;
25 import javax.xml.parsers.ParserConfigurationException JavaDoc;
26
27 import org.w3c.dom.Attr JavaDoc;
28 import org.w3c.dom.DOMException JavaDoc;
29 import org.w3c.dom.Document JavaDoc;
30 import org.w3c.dom.Element JavaDoc;
31 import org.w3c.dom.Node JavaDoc;
32 import org.xml.sax.Attributes JavaDoc;
33 import org.xml.sax.ContentHandler JavaDoc;
34 import org.xml.sax.SAXException JavaDoc;
35 import org.xml.sax.XMLReader JavaDoc;
36 import org.xml.sax.helpers.DefaultHandler JavaDoc;
37
38
39 /**
40  * A rule implementation that creates a DOM
41  * {@link org.w3c.dom.Node Node} containing the XML at the element that matched
42  * the rule. Two concrete types of nodes can be created by this rule:
43  * <ul>
44  * <li>the default is to create an {@link org.w3c.dom.Element Element} node.
45  * The created element will correspond to the element that matched the rule,
46  * containing all XML content underneath that element.</li>
47  * <li>alternatively, this rule can create nodes of type
48  * {@link org.w3c.dom.DocumentFragment DocumentFragment}, which will contain
49  * only the XML content under the element the rule was trigged on.</li>
50  * </ul>
51  * The created node will be normalized, meaning it will not contain text nodes
52  * that only contain white space characters.
53  *
54
55  *
56  * <p>The created <code>Node</code> will be pushed on Digester's object stack
57  * when done. To use it in the context of another DOM
58  * {@link org.w3c.dom.Document Document}, it must be imported first, using the
59  * Document method
60  * {@link org.w3c.dom.Document#importNode(org.w3c.dom.Node, boolean) importNode()}.
61  * </p>
62  *
63  * <p><strong>Important Note:</strong> This is implemented by replacing the SAX
64  * {@link org.xml.sax.ContentHandler ContentHandler} in the parser used by
65  * Digester, and resetting it when the matched element is closed. As a side
66  * effect, rules that would match XML nodes under the element that matches
67  * a <code>NodeCreateRule</code> will never be triggered by Digester, which
68  * usually is the behavior one would expect.</p>
69  *
70  * <p><strong>Note</strong> that the current implementation does not set the namespace prefixes
71  * in the exported nodes. The (usually more important) namespace URIs are set,
72  * of course.</p>
73  *
74  * @since Digester 1.4
75  */

76
77 public class NodeCreateRule extends Rule {
78
79
80     // ---------------------------------------------------------- Inner Classes
81

82
83     /**
84      * The SAX content handler that does all the actual work of assembling the
85      * DOM node tree from the SAX events.
86      */

87     private class NodeBuilder
88         extends DefaultHandler JavaDoc {
89
90
91         // ------------------------------------------------------- Constructors
92

93
94         /**
95          * Constructor.
96          *
97          * <p>Stores the content handler currently used by Digester so it can
98          * be reset when done, and initializes the DOM objects needed to
99          * build the node.</p>
100          *
101          * @param doc the document to use to create nodes
102          * @param root the root node
103          * @throws ParserConfigurationException if the DocumentBuilderFactory
104          * could not be instantiated
105          * @throws SAXException if the XMLReader could not be instantiated by
106          * Digester (should not happen)
107          */

108         public NodeBuilder(Document JavaDoc doc, Node JavaDoc root)
109             throws ParserConfigurationException JavaDoc, SAXException JavaDoc {
110
111             this.doc = doc;
112             this.root = root;
113             this.top = root;
114             
115             oldContentHandler = digester.getXMLReader().getContentHandler();
116
117         }
118
119
120         // ------------------------------------------------- Instance Variables
121

122
123         /**
124          * The content handler used by Digester before it was set to this
125          * content handler.
126          */

127         protected ContentHandler JavaDoc oldContentHandler = null;
128
129
130         /**
131          * Depth of the current node, relative to the element where the content
132          * handler was put into action.
133          */

134         protected int depth = 0;
135
136
137         /**
138          * A DOM Document used to create the various Node instances.
139          */

140         protected Document JavaDoc doc = null;
141
142
143         /**
144          * The DOM node that will be pushed on Digester's stack.
145          */

146         protected Node JavaDoc root = null;
147
148
149         /**
150          * The current top DOM mode.
151          */

152         protected Node JavaDoc top = null;
153
154
155         // --------------------------------------------- ContentHandler Methods
156

157
158         /**
159          * Appends a {@link org.w3c.dom.Text Text} node to the current node.
160          *
161          * @param ch the characters from the XML document
162          * @param start the start position in the array
163          * @param length the number of characters to read from the array
164          * @throws SAXException if the DOM implementation throws an exception
165          */

166         public void characters(char[] ch, int start, int length)
167             throws SAXException JavaDoc {
168
169             try {
170                 String JavaDoc str = new String JavaDoc(ch, start, length);
171                 if (str.trim().length() > 0) {
172                     top.appendChild(doc.createTextNode(str));
173                 }
174             } catch (DOMException JavaDoc e) {
175                 throw new SAXException JavaDoc(e.getMessage());
176             }
177
178         }
179
180
181         /**
182          * Checks whether control needs to be returned to Digester.
183          *
184          * @param namespaceURI the namespace URI
185          * @param localName the local name
186          * @param qName the qualified (prefixed) name
187          * @throws SAXException if the DOM implementation throws an exception
188          */

189         public void endElement(String JavaDoc namespaceURI, String JavaDoc localName,
190                                String JavaDoc qName)
191             throws SAXException JavaDoc {
192             
193             try {
194                 if (depth == 0) {
195                     getDigester().getXMLReader().setContentHandler(
196                         oldContentHandler);
197                     getDigester().push(root);
198                     getDigester().endElement(namespaceURI, localName, qName);
199                 }
200     
201                 top = top.getParentNode();
202                 depth--;
203             } catch (DOMException JavaDoc e) {
204                 throw new SAXException JavaDoc(e.getMessage());
205             }
206
207         }
208
209
210         /**
211          * Adds a new
212          * {@link org.w3c.dom.ProcessingInstruction ProcessingInstruction} to
213          * the current node.
214          *
215          * @param target the processing instruction target
216          * @param data the processing instruction data, or null if none was
217          * supplied
218          * @throws SAXException if the DOM implementation throws an exception
219          */

220         public void processingInstruction(String JavaDoc target, String JavaDoc data)
221             throws SAXException JavaDoc {
222             
223             try {
224                 top.appendChild(doc.createProcessingInstruction(target, data));
225             } catch (DOMException JavaDoc e) {
226                 throw new SAXException JavaDoc(e.getMessage());
227             }
228
229         }
230
231
232         /**
233          * Adds a new child {@link org.w3c.dom.Element Element} to the current
234          * node.
235          *
236          * @param namespaceURI the namespace URI
237          * @param localName the local name
238          * @param qName the qualified (prefixed) name
239          * @param atts the list of attributes
240          * @throws SAXException if the DOM implementation throws an exception
241          */

242         public void startElement(String JavaDoc namespaceURI, String JavaDoc localName,
243                                  String JavaDoc qName, Attributes JavaDoc atts)
244             throws SAXException JavaDoc {
245
246             try {
247                 Node JavaDoc previousTop = top;
248                 if ((localName == null) || (localName.length() == 0)) {
249                     top = doc.createElement(qName);
250                 } else {
251                     top = doc.createElementNS(namespaceURI, localName);
252                 }
253                 for (int i = 0; i < atts.getLength(); i++) {
254                     Attr JavaDoc attr = null;
255                     if ((atts.getLocalName(i) == null) ||
256                         (atts.getLocalName(i).length() == 0)) {
257                         attr = doc.createAttribute(atts.getQName(i));
258                         attr.setNodeValue(atts.getValue(i));
259                         ((Element JavaDoc)top).setAttributeNode(attr);
260                     } else {
261                         attr = doc.createAttributeNS(atts.getURI(i),
262                                                      atts.getLocalName(i));
263                         attr.setNodeValue(atts.getValue(i));
264                         ((Element JavaDoc)top).setAttributeNodeNS(attr);
265                     }
266                 }
267                 previousTop.appendChild(top);
268                 depth++;
269             } catch (DOMException JavaDoc e) {
270                 throw new SAXException JavaDoc(e.getMessage());
271             }
272
273         }
274
275     }
276
277
278     // ----------------------------------------------------------- Constructors
279

280
281     /**
282      * Default constructor. Creates an instance of this rule that will create a
283      * DOM {@link org.w3c.dom.Element Element}.
284      */

285     public NodeCreateRule() throws ParserConfigurationException JavaDoc {
286
287         this(Node.ELEMENT_NODE);
288
289     }
290
291
292     /**
293      * Constructor. Creates an instance of this rule that will create a DOM
294      * {@link org.w3c.dom.Element Element}, but lets you specify the JAXP
295      * <code>DocumentBuilder</code> that should be used when constructing the
296      * node tree.
297      *
298      * @param documentBuilder the JAXP <code>DocumentBuilder</code> to use
299      */

300     public NodeCreateRule(DocumentBuilder JavaDoc documentBuilder) {
301
302         this(Node.ELEMENT_NODE, documentBuilder);
303
304     }
305
306
307     /**
308      * Constructor. Creates an instance of this rule that will create either a
309      * DOM {@link org.w3c.dom.Element Element} or a DOM
310      * {@link org.w3c.dom.DocumentFragment DocumentFragment}, depending on the
311      * value of the <code>nodeType</code> parameter.
312      *
313      * @param nodeType the type of node to create, which can be either
314      * {@link org.w3c.dom.Node#ELEMENT_NODE Node.ELEMENT_NODE} or
315      * {@link org.w3c.dom.Node#DOCUMENT_FRAGMENT_NODE Node.DOCUMENT_FRAGMENT_NODE}
316      * @throws IllegalArgumentException if the node type is not supported
317      */

318     public NodeCreateRule(int nodeType) throws ParserConfigurationException JavaDoc {
319
320         this(nodeType,
321              DocumentBuilderFactory.newInstance().newDocumentBuilder());
322
323     }
324
325
326     /**
327      * Constructor. Creates an instance of this rule that will create either a
328      * DOM {@link org.w3c.dom.Element Element} or a DOM
329      * {@link org.w3c.dom.DocumentFragment DocumentFragment}, depending on the
330      * value of the <code>nodeType</code> parameter. This constructor lets you
331      * specify the JAXP <code>DocumentBuilder</code> that should be used when
332      * constructing the node tree.
333      *
334      * @param nodeType the type of node to create, which can be either
335      * {@link org.w3c.dom.Node#ELEMENT_NODE Node.ELEMENT_NODE} or
336      * {@link org.w3c.dom.Node#DOCUMENT_FRAGMENT_NODE Node.DOCUMENT_FRAGMENT_NODE}
337      * @param documentBuilder the JAXP <code>DocumentBuilder</code> to use
338      * @throws IllegalArgumentException if the node type is not supported
339      */

340     public NodeCreateRule(int nodeType, DocumentBuilder JavaDoc documentBuilder) {
341
342         if (!((nodeType == Node.DOCUMENT_FRAGMENT_NODE) ||
343               (nodeType == Node.ELEMENT_NODE))) {
344             throw new IllegalArgumentException JavaDoc(
345                 "Can only create nodes of type DocumentFragment and Element");
346         }
347         this.nodeType = nodeType;
348         this.documentBuilder = documentBuilder;
349
350     }
351
352
353     // ----------------------------------------------------- Instance Variables
354

355
356     /**
357      * The JAXP <code>DocumentBuilder</code> to use.
358      */

359     private DocumentBuilder JavaDoc documentBuilder = null;
360
361
362     /**
363      * The type of the node that should be created. Must be one of the
364      * constants defined in {@link org.w3c.dom.Node Node}, but currently only
365      * {@link org.w3c.dom.Node#ELEMENT_NODE Node.ELEMENT_NODE} and
366      * {@link org.w3c.dom.Node#DOCUMENT_FRAGMENT_NODE Node.DOCUMENT_FRAGMENT_NODE}
367      * are allowed values.
368      */

369     private int nodeType = Node.ELEMENT_NODE;
370
371
372     // ----------------------------------------------------------- Rule Methods
373

374
375     /**
376      * Implemented to replace the content handler currently in use by a
377      * NodeBuilder.
378      *
379      * @param namespaceURI the namespace URI of the matching element, or an
380      * empty string if the parser is not namespace aware or the element has
381      * no namespace
382      * @param name the local name if the parser is namespace aware, or just
383      * the element name otherwise
384      * @param attributes The attribute list of this element
385      * @throws Exception indicates a JAXP configuration problem
386      */

387     public void begin(String JavaDoc namespaceURI, String JavaDoc name, Attributes JavaDoc attributes)
388         throws Exception JavaDoc {
389
390         XMLReader JavaDoc xmlReader = getDigester().getXMLReader();
391         Document JavaDoc doc = documentBuilder.newDocument();
392         NodeBuilder builder = null;
393         if (nodeType == Node.ELEMENT_NODE) {
394             Element JavaDoc element = null;
395             if (getDigester().getNamespaceAware()) {
396                 element =
397                     doc.createElementNS(namespaceURI, name);
398                 for (int i = 0; i < attributes.getLength(); i++) {
399                     element.setAttributeNS(attributes.getURI(i),
400                                            attributes.getLocalName(i),
401                                            attributes.getValue(i));
402                 }
403             } else {
404                 element = doc.createElement(name);
405                 for (int i = 0; i < attributes.getLength(); i++) {
406                     element.setAttribute(attributes.getQName(i),
407                                          attributes.getValue(i));
408                 }
409             }
410             builder = new NodeBuilder(doc, element);
411         } else {
412             builder = new NodeBuilder(doc, doc.createDocumentFragment());
413         }
414         xmlReader.setContentHandler(builder);
415
416     }
417
418
419     /**
420      * Pop the Node off the top of the stack.
421      */

422     public void end() throws Exception JavaDoc {
423
424         Object JavaDoc top = digester.pop();
425
426     }
427
428
429 }
430
Popular Tags