KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > velocity > anakia > NodeList


1 package org.apache.velocity.anakia;
2
3 /*
4  * Copyright 2001,2004 The Apache Software Foundation.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * 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 import java.io.Writer JavaDoc;
20 import java.io.IOException JavaDoc;
21 import java.io.StringWriter JavaDoc;
22 import java.util.*;
23 import org.jdom.*;
24 import org.jdom.output.*;
25
26 /**
27  * Provides a class for wrapping a list of JDOM objects primarily for use in template
28  * engines and other kinds of text transformation tools.
29  * It has a {@link #toString()} method that will output the XML serialized form of the
30  * nodes it contains - again focusing on template engine usage, as well as the
31  * {@link #selectNodes(String)} method that helps selecting a different set of nodes
32  * starting from the nodes in this list. The class also implements the {@link java.util.List}
33  * interface by simply delegating calls to the contained list (the {@link #subList(int, int)}
34  * method is implemented by delegating to the contained list and wrapping the returned
35  * sublist into a <code>NodeList</code>).
36  *
37  * @author <a HREF="mailto:szegedia@freemail.hu">Attila Szegedi</a>
38  * @version $Id: NodeList.java,v 1.2.4.1 2004/03/03 23:22:04 geirm Exp $
39  */

40 public class NodeList implements List, Cloneable JavaDoc
41 {
42     private static final AttributeXMLOutputter DEFAULT_OUTPUTTER =
43         new AttributeXMLOutputter();
44     
45     /** The contained nodes */
46     private List nodes;
47
48     /**
49      * Creates an empty node list.
50      */

51     public NodeList()
52     {
53         nodes = new ArrayList();
54     }
55
56     /**
57      * Creates a node list that holds a single {@link Document} node.
58      */

59     public NodeList(Document document)
60     {
61         this((Object JavaDoc)document);
62     }
63
64     /**
65      * Creates a node list that holds a single {@link Element} node.
66      */

67     public NodeList(Element element)
68     {
69         this((Object JavaDoc)element);
70     }
71
72     private NodeList(Object JavaDoc object)
73     {
74         if(object == null)
75         {
76             throw new IllegalArgumentException JavaDoc(
77                 "Cannot construct NodeList with null.");
78         }
79         nodes = new ArrayList(1);
80         nodes.add(object);
81     }
82     
83     /**
84      * Creates a node list that holds a list of nodes.
85      * @param nodes the list of nodes this template should hold. The created
86      * template will copy the passed nodes list, so changes to the passed list
87      * will not affect the model.
88      */

89     public NodeList(List nodes)
90     {
91         this(nodes, true);
92     }
93     
94     /**
95      * Creates a node list that holds a list of nodes.
96      * @param nodes the list of nodes this template should hold.
97      * @param copy if true, the created template will copy the passed nodes
98      * list, so changes to the passed list will not affect the model. If false,
99      * the model will reference the passed list and will sense changes in it,
100      * altough no operations on the list will be synchronized.
101      */

102     public NodeList(List nodes, boolean copy)
103     {
104         if(nodes == null)
105         {
106             throw new IllegalArgumentException JavaDoc(
107                 "Cannot initialize NodeList with null list");
108         }
109         this.nodes = copy ? new ArrayList(nodes) : nodes;
110     }
111     
112     /**
113      * Retrieves the underlying list used to store the nodes. Note however, that
114      * you can fully use the underlying list through the <code>List</code> interface
115      * of this class itself. You would probably access the underlying list only for
116      * synchronization purposes.
117      */

118     public List getList()
119     {
120         return nodes;
121     }
122
123     /**
124      * This method returns the string resulting from concatenation of string
125      * representations of its nodes. Each node is rendered using its XML
126      * serialization format. This greatly simplifies creating XML-transformation
127      * templates, as to output a node contained in variable x as XML fragment,
128      * you simply write ${x} in the template (or whatever your template engine
129      * uses as its expression syntax).
130      */

131     public String JavaDoc toString()
132     {
133         if(nodes.isEmpty())
134         {
135             return "";
136         }
137
138         StringWriter JavaDoc sw = new StringWriter JavaDoc(nodes.size() * 128);
139         try
140         {
141             for(Iterator i = nodes.iterator(); i.hasNext();)
142             {
143                 Object JavaDoc node = i.next();
144                 if(node instanceof Element)
145                 {
146                     DEFAULT_OUTPUTTER.output((Element)node, sw);
147                 }
148                 else if(node instanceof Attribute)
149                 {
150                     DEFAULT_OUTPUTTER.output((Attribute)node, sw);
151                 }
152                 else if(node instanceof Text)
153                 {
154                     DEFAULT_OUTPUTTER.output((Text)node, sw);
155                 }
156                 else if(node instanceof Document)
157                 {
158                     DEFAULT_OUTPUTTER.output((Document)node, sw);
159                 }
160                 else if(node instanceof ProcessingInstruction)
161                 {
162                     DEFAULT_OUTPUTTER.output((ProcessingInstruction)node, sw);
163                 }
164                 else if(node instanceof Comment)
165                 {
166                     DEFAULT_OUTPUTTER.output((Comment)node, sw);
167                 }
168                 else if(node instanceof CDATA)
169                 {
170                     DEFAULT_OUTPUTTER.output((CDATA)node, sw);
171                 }
172                 else if(node instanceof DocType)
173                 {
174                     DEFAULT_OUTPUTTER.output((DocType)node, sw);
175                 }
176                 else if(node instanceof EntityRef)
177                 {
178                     DEFAULT_OUTPUTTER.output((EntityRef)node, sw);
179                 }
180                 else
181                 {
182                     throw new IllegalArgumentException JavaDoc(
183                         "Cannot process a " +
184                         (node == null
185                          ? "null node"
186                          : "node of class " + node.getClass().getName()));
187                 }
188             }
189         }
190         catch(IOException JavaDoc e)
191         {
192             // Cannot happen as we work with a StringWriter in memory
193
throw new Error JavaDoc();
194         }
195         return sw.toString();
196     }
197
198     /**
199      * Returns a NodeList that contains the same nodes as this node list.
200      * @throws CloneNotSupportedException if the contained list's class does
201      * not have an accessible no-arg constructor.
202      */

203     public Object JavaDoc clone()
204         throws CloneNotSupportedException JavaDoc
205     {
206         NodeList clonedList = (NodeList)super.clone();
207         clonedList.cloneNodes();
208         return clonedList;
209     }
210     
211     private void cloneNodes()
212         throws CloneNotSupportedException JavaDoc
213     {
214         Class JavaDoc listClass = nodes.getClass();
215         try
216         {
217             List clonedNodes = (List)listClass.newInstance();
218             clonedNodes.addAll(nodes);
219             nodes = clonedNodes;
220         }
221         catch(IllegalAccessException JavaDoc e)
222         {
223             throw new CloneNotSupportedException JavaDoc("Cannot clone NodeList since"
224             + " there is no accessible no-arg constructor on class "
225             + listClass.getName());
226         }
227         catch(InstantiationException JavaDoc e)
228         {
229             // Cannot happen as listClass represents a concrete, non-primitive,
230
// non-array, non-void class - there's an instance of it in "nodes"
231
// which proves these assumptions.
232
throw new Error JavaDoc();
233         }
234     }
235
236     /**
237      * Returns the hash code of the contained list.
238      */

239     public int hashCode()
240     {
241         return nodes.hashCode();
242     }
243     
244     /**
245      * Tests for equality with another object.
246      * @param o the object to test for equality
247      * @return true if the other object is also a NodeList and their contained
248      * {@link List} objects evaluate as equals.
249      */

250     public boolean equals(Object JavaDoc o)
251     {
252         return o instanceof NodeList
253             ? ((NodeList)o).nodes.equals(nodes)
254             : false;
255     }
256     
257     /**
258      * Applies an XPath expression to the node list and returns the resulting
259      * node list. In order for this method to work, your application must have
260      * access to <a HREF="http://code.werken.com">werken.xpath</a> library
261      * classes. The implementation does cache the parsed format of XPath
262      * expressions in a weak hash map, keyed by the string representation of
263      * the XPath expression. As the string object passed as the argument is
264      * usually kept in the parsed template, this ensures that each XPath
265      * expression is parsed only once during the lifetime of the template that
266      * first invoked it.
267      * @param xpathExpression the XPath expression you wish to apply
268      * @return a NodeList representing the nodes that are the result of
269      * application of the XPath to the current node list. It can be empty.
270      */

271     public NodeList selectNodes(String JavaDoc xpathString)
272     {
273         return new NodeList(XPathCache.getXPath(xpathString).applyTo(nodes), false);
274     }
275
276 // List methods implemented hereafter
277

278     public boolean add(Object JavaDoc o)
279     {
280         return nodes.add(o);
281     }
282
283     public void add(int index, Object JavaDoc o)
284     {
285         nodes.add(index, o);
286     }
287
288     public boolean addAll(Collection c)
289     {
290         return nodes.addAll(c);
291     }
292
293     public boolean addAll(int index, Collection c)
294     {
295         return nodes.addAll(index, c);
296     }
297
298     public void clear()
299     {
300         nodes.clear();
301     }
302
303     public boolean contains(Object JavaDoc o)
304     {
305         return nodes.contains(o);
306     }
307
308     public boolean containsAll(Collection c)
309     {
310         return nodes.containsAll(c);
311     }
312
313     public Object JavaDoc get(int index)
314     {
315         return nodes.get(index);
316     }
317
318     public int indexOf(Object JavaDoc o)
319     {
320         return nodes.indexOf(o);
321     }
322
323     public boolean isEmpty()
324     {
325         return nodes.isEmpty();
326     }
327
328     public Iterator iterator()
329     {
330         return nodes.iterator();
331     }
332
333     public int lastIndexOf(Object JavaDoc o)
334     {
335         return nodes.lastIndexOf(o);
336     }
337
338     public ListIterator listIterator()
339     {
340         return nodes.listIterator();
341     }
342
343     public ListIterator listIterator(int index)
344     {
345         return nodes.listIterator(index);
346     }
347
348     public Object JavaDoc remove(int index)
349     {
350         return nodes.remove(index);
351     }
352
353     public boolean remove(Object JavaDoc o)
354     {
355         return nodes.remove(o);
356     }
357
358     public boolean removeAll(Collection c)
359     {
360         return nodes.removeAll(c);
361     }
362
363     public boolean retainAll(Collection c)
364     {
365         return nodes.retainAll(c);
366     }
367
368     public Object JavaDoc set(int index, Object JavaDoc o)
369     {
370         return nodes.set(index, o);
371     }
372
373     public int size()
374     {
375         return nodes.size();
376     }
377
378     public List subList(int fromIndex, int toIndex)
379     {
380         return new NodeList(nodes.subList(fromIndex, toIndex));
381     }
382
383     public Object JavaDoc[] toArray()
384     {
385         return nodes.toArray();
386     }
387
388     public Object JavaDoc[] toArray(Object JavaDoc[] a)
389     {
390         return nodes.toArray(a);
391     }
392
393     /**
394      * A special subclass of XMLOutputter that will be used to output
395      * Attribute nodes. As a subclass of XMLOutputter it can use its protected
396      * method escapeAttributeEntities() to serialize the attribute
397      * appropriately.
398      */

399     private static final class AttributeXMLOutputter extends XMLOutputter
400     {
401         public void output(Attribute attribute, Writer JavaDoc out)
402             throws IOException JavaDoc
403         {
404             out.write(" ");
405             out.write(attribute.getQualifiedName());
406             out.write("=");
407             
408             out.write("\"");
409             out.write(escapeAttributeEntities(attribute.getValue()));
410             out.write("\"");
411         }
412     }
413 }
414
Popular Tags