2009/05/20 - Apache Shale has been retired.

For more information, please explore the Attic.

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  /*
19   * $Id: Node.java 468624 2006-10-28 03:13:24Z gvanmatre $
20   */
21  package org.apache.shale.clay.parser;
22  
23  import java.util.ArrayList;
24  import java.util.Iterator;
25  import java.util.List;
26  import java.util.Map;
27  import java.util.TreeMap;
28  
29  
30  /***
31   * <p>This class represents a node within a parsed document.</p>
32   */
33  public class Node {
34  
35      /***
36       * <p>Indicates the node is a comment or within a comment
37       * block.</p>
38       */
39      private boolean isComment = false;
40  
41      /***
42       * <p>Indicates the node is a starting node.</p>
43       */
44      private boolean isStart = false;
45  
46      /***
47       * <p>Indicates the node is a ending node.</p>
48       */
49      private boolean isEnd = false;
50  
51  
52      /***
53       * <p>This flag indicates the node is a CDATA node.</p>
54       */
55      private boolean isCdata = false;
56  
57      /***
58       * <p>This boolean flag has a <code>true</code> value if the
59       * node has a starting and ending node.  Not all nodes will be
60       * well formed.  Inline text or comments are not well formed.
61       * </p>
62       */
63      private boolean isWellFormed = false;
64  
65      /***
66       * <p>Qualified name.  This won't be used in HTML documents</p>
67       */
68      private String qname = null;
69  
70      /***
71       * <p>The node name.</p>
72       */
73      private String name = null;
74  
75      /***
76       * <p>Value pair tags within the body of the starting node.</p>
77       */
78      private Map attributes = new TreeMap();
79  
80      /***
81       * <p>An object instance implementing the {@link Token} interface.
82       * This object represents a starting and ending offset within the
83       * document</p>
84       */
85      private Token token = null;
86  
87      /***
88       * <p>Child nodes within the document.  These nodes will fall within
89       * the beginning and ending node makers</p>
90       */
91      private List children = new ArrayList();
92  
93      /***
94       * <p>All nodes but top-level nodes will have a parent node.  Because
95       * the {@link Parser} can work through a incomplete and not well formed
96       * HTML fragment, there may be several top-level nodes</p>
97       */
98      private Node parent = null;
99  
100     /***
101      * <p>Returns <code>true</code> if the node has a beginning and ending
102      * marker.</p>
103      *
104      * @return <code>true</code> if node is well-formed
105      */
106     public boolean isWellFormed() {
107         return isWellFormed;
108     }
109 
110     /***
111      * <p>Sets a boolean flag that is <code>true</code> if the node has a
112      * beginning and ending marker.</p>
113      *
114      * @param isWellFormed indicates if the node is well-formed
115      */
116     public void setWellFormed(boolean isWellFormed) {
117         this.isWellFormed = isWellFormed;
118     }
119 
120     /***
121      * <p>Returns the parent of the node or <code>null</code> if the node
122      * is a top-level/root node.</p>
123      *
124      * @return parent node
125      */
126     public Node getParent() {
127         return parent;
128     }
129 
130     /***
131      * <p>Sets the parent node.</p>
132      *
133      * @param parent nodes parent
134      */
135     public void setParent(Node parent) {
136         this.parent = parent;
137     }
138 
139     /***
140      * <p>Returns a <code>List</code> of child nodes.</p>
141      *
142      * @return children of this node
143      */
144     public List getChildren() {
145         return children;
146     }
147 
148     /***
149      * <p>Adds a child node to the <code>children</code> collection.</p>
150      *
151      * @param child added to this node
152      */
153     public void addChild(Node child) {
154         child.setParent(this);
155         children.add(child);
156     }
157 
158     /***
159      * <p>Overloaded constructor that requires a {@link Token} object
160      * in the formal parameter.</p>
161      *
162      * @param token document token offset of this node
163      */
164     public Node(Token token) {
165         this.token = token;
166     }
167 
168     /***
169      * <p>Returns an object that represents the starting and ending offsets
170      * within the document that this node represents.</p>
171      *
172      * @return document offset token for this node
173      */
174     public Token getToken() {
175         return token;
176     }
177 
178     /***
179      * <p>Returns a <code>true</code> value if this node is a ending marker.</p>
180      *
181      * @return <code>true</code> if this is a ending node
182      */
183     public boolean isEnd() {
184         return isEnd;
185     }
186 
187     /***
188      * <p>Sets the flag indicating that this node is a ending marker.</p>
189      *
190      * @param isEnd indicates ending marker
191      */
192     public void setEnd(boolean isEnd) {
193         this.isEnd = isEnd;
194     }
195 
196     /***
197      * <p>Returns a Map collection of node attributes.</p>
198      *
199      * @return node attributes
200      */
201     public Map getAttributes() {
202         return attributes;
203     }
204 
205     /***
206      * <p>Sets a Map collection of Node attributes.</p>
207      *
208      * @param attributes of the node
209      */
210     public void setAttributes(Map attributes) {
211         this.attributes = attributes;
212     }
213 
214     /***
215      * <p>Returns <code>true</code> if the node is a beginning marker.</p>
216      *
217      * @return <code>true</code> if a beginning marker
218      */
219     public boolean isStart() {
220         return isStart;
221     }
222 
223     /***
224      * <p>Sets a boolean flag indicating that the node is a beginning marker.</p>
225      *
226      * @param isStart beginning marker flag
227      */
228     public void setStart(boolean isStart) {
229         this.isStart = isStart;
230     }
231 
232     /***
233      * <p>Returns the node name.</p>
234      *
235      * @return name of the ndoe
236      */
237     public String getName() {
238         return name;
239     }
240 
241     /***
242      * <p>Sets the node name.</p>
243      *
244      * @param name of the node
245      */
246     public void setName(String name) {
247         this.name = name;
248     }
249 
250     /***
251      * <p>Returns the qualified node name.</p>
252      *
253      * @return the namespace prefix of the node
254      */
255     public String getQname() {
256         return qname;
257     }
258 
259     /***
260      * <p>Sets the qualified node name.</p>
261      *
262      * @param qname namespace prefix of the node
263      */
264     public void setQname(String qname) {
265         this.qname = qname;
266     }
267 
268     /***
269      * @return Describes the objects state
270      */
271     public String toString() {
272         StringBuffer buff = new StringBuffer();
273         buff.append("name=").append(name).append(" isStart=").append(isStart)
274         .append(" isEnd=").append(isEnd).append(" isWellFormed=")
275         .append(isWellFormed).append(" isComment=").append(isComment)
276         .append(" isCdata=").append(isCdata)
277         .append("\n").append(token).append("\n").append(attributes);
278         return buff.toString();
279     }
280 
281     /***
282      * <p> Returns <code>true</code> if the node is
283      * a comment; otherwise; the default is <code>false</code>.
284      * </p>.
285      *
286      * @return <code>true</code> if node is a comment or in a comment
287      */
288     public boolean isComment() {
289         return isComment;
290     }
291 
292 
293     /***
294      * <p>Sets a boolean value that identifies this node as
295      * being a comment.  This could be a starting, ending or
296      * within the body.</p>
297      *
298      * @param isComment indicates node is or is in a comment block
299      */
300     public void setComment(boolean isComment) {
301         this.isComment = isComment;
302     }
303 
304 
305     /***
306      * <p> Returns <code>true</code> if the node is
307      * a CDATA; otherwise; the default is <code>false</code>.
308      * </p>.
309      *
310      * @return <code>true</code> if the node is or is in a CDATA block
311      */
312     public boolean isCdata() {
313         return isCdata;
314     }
315 
316 
317     /***
318      * <p>Sets a boolean value that identifies this node as
319      * being a CDATA.  This could be a starting, ending or
320      * within the body.</p>
321      *
322      * @param isCdata indicates the node is in a cdata block
323      */
324     public void setCdata(boolean isCdata) {
325         this.isCdata = isCdata;
326     }
327 
328     /***
329      * <p>Finds matching nodes by <code>name</code> searching thru all the children.</p>
330      *
331      * @param name of the target node
332      * @return list of nodes found by name
333      */
334     public List getNodesByName(String name) {
335         List nodes = new ArrayList();
336         findNodesByName(this, name, nodes);
337         return nodes;
338     }
339 
340     /***
341      * <p>Recursively walks down the tree looking for nodes matching the <code>name</code>.</p>
342      *
343      * @param node markup
344      * @param name searched argument
345      * @param nodes nodes in the hierarchy matched by name
346      */
347     private void findNodesByName(Node node, String name, List nodes) {
348         if (node.getName() != null && node.getName().equals(name)) {
349             nodes.add(node);
350         }
351 
352         Iterator ni = node.getChildren().iterator();
353         while (ni.hasNext()) {
354             Node child = (Node) ni.next();
355             findNodesByName(child, name, nodes);
356         }
357 
358     }
359 
360     /***
361      * <p>Walks up the tree looking for a uri namespace matching the <code>prefix</code>.
362      * A <code>null</code> prefix will search for the default uri namespace.</p>
363      *
364      * @param prefix node qname namespace prefix
365      * @return url matching the namespace prefix
366      */
367     public String getNamespaceURI(String prefix) {
368         StringBuffer attributeName = new StringBuffer("xmlns");
369         if (prefix != null && prefix.length() > 0) {
370             attributeName.append(":").append(prefix);
371         }
372 
373         String uri = (String) attributes.get(attributeName.toString());
374 
375         if (uri != null) {
376             return uri;
377         }
378 
379         Node parent = getParent();
380         while (parent != null) {
381             uri = (String) parent.getAttributes().get(attributeName.toString());
382             if (uri != null) {
383                 return uri;
384             } else {
385                 parent = parent.getParent();
386             }
387         }
388 
389 
390         return null;
391     }
392 
393 }