View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    * 
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   * 
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.struts2.jasper.xmlparser;
19  
20  import java.util.ArrayList;
21  import java.util.Collections;
22  import java.util.HashMap;
23  import java.util.Iterator;
24  
25  
26  /***
27   * Simplified implementation of a Node from a Document Object Model (DOM)
28   * parse of an XML document.  This class is used to represent a DOM tree
29   * so that the XML parser's implementation of <code>org.w3c.dom</code> need
30   * not be visible to the remainder of Jasper.
31   * <p/>
32   * <strong>WARNING</strong> - Construction of a new tree, or modifications
33   * to an existing one, are not thread-safe and such accesses must be
34   * synchronized.
35   *
36   * @author Craig R. McClanahan
37   * @version $Revision: 466606 $ $Date: 2006-10-21 17:07:12 -0600 (Sat, 21 Oct 2006) $
38   */
39  
40  public class TreeNode {
41  
42  
43      // ----------------------------------------------------------- Constructors
44  
45  
46      /***
47       * Construct a new node with no parent.
48       *
49       * @param name The name of this node
50       */
51      public TreeNode(String name) {
52  
53          this(name, null);
54  
55      }
56  
57  
58      /***
59       * Construct a new node with the specified parent.
60       *
61       * @param name   The name of this node
62       * @param parent The node that is the parent of this node
63       */
64      public TreeNode(String name, TreeNode parent) {
65  
66          super();
67          this.name = name;
68          this.parent = parent;
69          if (this.parent != null)
70              this.parent.addChild(this);
71  
72      }
73  
74  
75      // ----------------------------------------------------- Instance Variables
76  
77  
78      /***
79       * The attributes of this node, keyed by attribute name,
80       * Instantiated only if required.
81       */
82      protected HashMap attributes = null;
83  
84  
85      /***
86       * The body text associated with this node (if any).
87       */
88      protected String body = null;
89  
90  
91      /***
92       * The children of this node, instantiated only if required.
93       */
94      protected ArrayList children = null;
95  
96  
97      /***
98       * The name of this node.
99       */
100     protected String name = null;
101 
102 
103     /***
104      * The parent node of this node.
105      */
106     protected TreeNode parent = null;
107 
108 
109     // --------------------------------------------------------- Public Methods
110 
111 
112     /***
113      * Add an attribute to this node, replacing any existing attribute
114      * with the same name.
115      *
116      * @param name  The attribute name to add
117      * @param value The new attribute value
118      */
119     public void addAttribute(String name, String value) {
120 
121         if (attributes == null)
122             attributes = new HashMap();
123         attributes.put(name, value);
124 
125     }
126 
127 
128     /***
129      * Add a new child node to this node.
130      *
131      * @param node The new child node
132      */
133     public void addChild(TreeNode node) {
134 
135         if (children == null)
136             children = new ArrayList();
137         children.add(node);
138 
139     }
140 
141 
142     /***
143      * Return the value of the specified node attribute if it exists, or
144      * <code>null</code> otherwise.
145      *
146      * @param name Name of the requested attribute
147      */
148     public String findAttribute(String name) {
149 
150         if (attributes == null)
151             return (null);
152         else
153             return ((String) attributes.get(name));
154 
155     }
156 
157 
158     /***
159      * Return an Iterator of the attribute names of this node.  If there are
160      * no attributes, an empty Iterator is returned.
161      */
162     public Iterator findAttributes() {
163 
164         if (attributes == null)
165             return (Collections.EMPTY_LIST.iterator());
166         else
167             return (attributes.keySet().iterator());
168 
169     }
170 
171 
172     /***
173      * Return the first child node of this node with the specified name,
174      * if there is one; otherwise, return <code>null</code>.
175      *
176      * @param name Name of the desired child element
177      */
178     public TreeNode findChild(String name) {
179 
180         if (children == null)
181             return (null);
182         Iterator items = children.iterator();
183         while (items.hasNext()) {
184             TreeNode item = (TreeNode) items.next();
185             if (name.equals(item.getName()))
186                 return (item);
187         }
188         return (null);
189 
190     }
191 
192 
193     /***
194      * Return an Iterator of all children of this node.  If there are no
195      * children, an empty Iterator is returned.
196      */
197     public Iterator findChildren() {
198 
199         if (children == null)
200             return (Collections.EMPTY_LIST.iterator());
201         else
202             return (children.iterator());
203 
204     }
205 
206 
207     /***
208      * Return an Iterator over all children of this node that have the
209      * specified name.  If there are no such children, an empty Iterator
210      * is returned.
211      *
212      * @param name Name used to select children
213      */
214     public Iterator findChildren(String name) {
215 
216         if (children == null)
217             return (Collections.EMPTY_LIST.iterator());
218 
219         ArrayList results = new ArrayList();
220         Iterator items = children.iterator();
221         while (items.hasNext()) {
222             TreeNode item = (TreeNode) items.next();
223             if (name.equals(item.getName()))
224                 results.add(item);
225         }
226         return (results.iterator());
227 
228     }
229 
230 
231     /***
232      * Return the body text associated with this node (if any).
233      */
234     public String getBody() {
235 
236         return (this.body);
237 
238     }
239 
240 
241     /***
242      * Return the name of this node.
243      */
244     public String getName() {
245 
246         return (this.name);
247 
248     }
249 
250 
251     /***
252      * Remove any existing value for the specified attribute name.
253      *
254      * @param name The attribute name to remove
255      */
256     public void removeAttribute(String name) {
257 
258         if (attributes != null)
259             attributes.remove(name);
260 
261     }
262 
263 
264     /***
265      * Remove a child node from this node, if it is one.
266      *
267      * @param node The child node to remove
268      */
269     public void removeNode(TreeNode node) {
270 
271         if (children != null)
272             children.remove(node);
273 
274     }
275 
276 
277     /***
278      * Set the body text associated with this node (if any).
279      *
280      * @param body The body text (if any)
281      */
282     public void setBody(String body) {
283 
284         this.body = body;
285 
286     }
287 
288 
289     /***
290      * Return a String representation of this TreeNode.
291      */
292     public String toString() {
293 
294         StringBuffer sb = new StringBuffer();
295         toString(sb, 0, this);
296         return (sb.toString());
297 
298     }
299 
300 
301     // ------------------------------------------------------ Protected Methods
302 
303 
304     /***
305      * Append to the specified StringBuffer a character representation of
306      * this node, with the specified amount of indentation.
307      *
308      * @param sb     The StringBuffer to append to
309      * @param indent Number of characters of indentation
310      * @param node   The TreeNode to be printed
311      */
312     protected void toString(StringBuffer sb, int indent,
313                             TreeNode node) {
314 
315         int indent2 = indent + 2;
316 
317         // Reconstruct an opening node
318         for (int i = 0; i < indent; i++)
319             sb.append(' ');
320         sb.append('<');
321         sb.append(node.getName());
322         Iterator names = node.findAttributes();
323         while (names.hasNext()) {
324             sb.append(' ');
325             String name = (String) names.next();
326             sb.append(name);
327             sb.append("=\"");
328             String value = node.findAttribute(name);
329             sb.append(value);
330             sb.append("\"");
331         }
332         sb.append(">\n");
333 
334         // Reconstruct the body text of this node (if any)
335         String body = node.getBody();
336         if ((body != null) && (body.length() > 0)) {
337             for (int i = 0; i < indent2; i++)
338                 sb.append(' ');
339             sb.append(body);
340             sb.append("\n");
341         }
342 
343         // Reconstruct child nodes with extra indentation
344         Iterator children = node.findChildren();
345         while (children.hasNext()) {
346             TreeNode child = (TreeNode) children.next();
347             toString(sb, indent2, child);
348         }
349 
350         // Reconstruct a closing node marker
351         for (int i = 0; i < indent; i++)
352             sb.append(' ');
353         sb.append("</");
354         sb.append(node.getName());
355         sb.append(">\n");
356 
357     }
358 
359 
360 }