2009/05/20 - Apache Shale has been retired.
For more information, please explore the Attic.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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 }