Source code: com/aendvari/common/model/xalan/XalanModelNode.java
1 /*
2 * XalanModelNode.java
3 *
4 * Copyright (c) 2001, 2002 Aendvari, Ltd. All Rights Reserved.
5 *
6 * See the file LICENSE for terms of use.
7 *
8 */
9
10 package com.aendvari.common.model.xalan;
11
12 import java.util.*;
13 import java.io.*;
14
15 import org.w3c.dom.Node;
16 import org.w3c.dom.NodeList;
17 import org.w3c.dom.NamedNodeMap;
18 import org.w3c.dom.Attr;
19
20 import com.aendvari.common.model.*;
21
22
23 /**
24 * <p>A Xalan XML implementation of the {@link ModelNode} interface.</p>
25 *
26 * @author Scott Milne
27 *
28 */
29
30 public class XalanModelNode implements ModelNode
31 {
32 /* Variables */
33
34 /** The owning model tree. */
35 protected XalanModelTree owner;
36
37 /** The DOM node */
38 protected Node modelNode;
39
40 /** The node value. */
41 protected String modelValue;
42
43
44 /* Constructors. */
45
46
47 /**
48 * Constructs a <code>XalanModelNode</code> instance.
49 *
50 * @param setOwner The owning {@link XalanModelTree}.
51 *
52 */
53
54 protected XalanModelNode(XalanModelTree setOwner)
55 {
56 owner = setOwner;
57
58 modelNode = null;
59 modelValue = null;
60 }
61
62 /**
63 * Constructs a <code>XalanModelNode</code> instance wrapping the supplied {@link Node}.
64 *
65 * @param setOwner The owning {@link XalanModelTree}.
66 * @param setModelNode The XML {@link Node} to wrap.
67 *
68 */
69
70 protected XalanModelNode( XalanModelTree setOwner, Node setModelNode )
71 {
72 owner = setOwner;
73
74 modelNode = setModelNode;
75 setXmlValue();
76 }
77
78
79 /* Accessors. */
80
81
82 /**
83 * This is used in XalanModelTree::getNode()
84 *
85 * @param setOwner The owning {@link XalanModelTree}.
86 *
87 */
88
89 protected XalanModelNode( XalanModelTree setOwner, String setModelValue )
90 {
91 owner = setOwner;
92
93 modelNode = null;
94 modelValue = setModelValue;
95 }
96
97 /**
98 * Sets the internal XML {@link Node} object wrapped by this {@link ModelNode}.
99 *
100 * @param setModelNode The XML {@link Node} to wrap.
101 *
102 */
103
104 public void setXmlNode( Node setModelNode )
105 {
106 modelNode = setModelNode;
107 setXmlValue();
108 }
109
110 /**
111 * Returns the internal XML {@link Node} object wrapped by this {@link ModelNode}.
112 *
113 * @return The XML {@link Node} wrapped by this {@link ModelNode}.
114 *
115 */
116
117 public Node getXmlNode()
118 {
119 return modelNode;
120 }
121
122 /**
123 * Caches the value of the XML {@link Node}, if any.
124 *
125 */
126
127 protected void setXmlValue()
128 {
129 // retrieve value from Node
130 if (modelNode != null)
131 {
132 if (modelNode.getNodeValue() != null)
133 // get the value directly from the node
134 modelValue = modelNode.getNodeValue();
135 else
136 // get the value from the internal text node
137 modelValue = getTextValue();
138 }
139 else
140 modelValue = "";
141 }
142
143 /**
144 * Returns the instance of <code>ModelTree</code> from which the {@link ModelNode} is within.
145 *
146 * @return The {@link ModelTree} instance this node is within.
147 *
148 */
149
150 public ModelTree getOwnerModelTree()
151 {
152 return owner;
153 }
154
155 /**
156 * Returns the value of the node.
157 *
158 * @return A String value of the node.
159 *
160 */
161
162 public String getNodeValue()
163 {
164 return modelValue;
165 }
166
167 /**
168 * Returns the text within the node.
169 *
170 * @return The value of the text node within this node.
171 *
172 */
173
174 protected String getTextValue()
175 {
176 Node node = modelNode.getFirstChild();
177
178 // scan for first text node
179 while (node != null)
180 {
181 if (node.getNodeType() == Node.TEXT_NODE)
182 {
183 return node.getNodeValue();
184 }
185
186 node = node.getNextSibling();
187 }
188
189 return "";
190 }
191
192 /**
193 * Sets the value of the node.
194 *
195 * @param A String value for the node.
196 *
197 */
198
199 public void setNodeValue( String value )
200 {
201 // state DOM modification
202 owner.setModified();
203
204 // place value into XML Node
205 if (modelNode != null)
206 {
207 modelNode.setNodeValue(value);
208 }
209
210 // place value into node string
211 if (value == null)
212 modelValue = "";
213 else
214 modelValue = value;
215 }
216
217 /**
218 * Returns the name of this node.
219 *
220 * @return The name of this node.
221 *
222 */
223
224 public String getNodeName()
225 {
226 return modelNode.getNodeName();
227 }
228
229 /**
230 * Returns a string representation of the node's position in the hierarchy.
231 *
232 * @return The position of this node in the hierarchy.
233 *
234 */
235
236 public String getNodePath()
237 {
238 LinkedList nodes = new LinkedList();
239
240 // traverse node tree upwards, and collect the nodes
241 Node node = modelNode;
242
243 do
244 {
245 nodes.addFirst(node);
246 node = node.getParentNode();
247 }
248 while (node != null);
249
250 // traverse back down tree, and create topic path
251 Iterator nodeIterator = nodes.iterator();
252 StringBuffer path = new StringBuffer();
253
254 // skip the root node
255 nodeIterator.next();
256
257 while (nodeIterator.hasNext())
258 {
259 // get the node at this level
260 node = (Node)nodeIterator.next();
261
262 path.append('/');
263 path.append(node.getNodeName());
264 }
265
266 return path.toString();
267 }
268
269 /**
270 * Returns the attributes of this node.
271 *
272 * @return A <code>Map</code> of all attibutes.
273 *
274 */
275
276 public Map getAttributes()
277 {
278 HashMap attributes = new HashMap();
279 NamedNodeMap nodeMap = modelNode.getAttributes();
280
281 if (nodeMap != null)
282 {
283 int count = nodeMap.getLength();
284 int index;
285
286 // extract each attribute node
287 for (index = 0; index < count; index++)
288 {
289 Node attribute = nodeMap.item(index);
290
291 // add attribute to output map
292 attributes.put(attribute.getNodeName(), attribute.getNodeValue());
293 }
294 }
295
296 return attributes;
297 }
298
299 /**
300 * Returns the string value of the specified attribute.
301 *
302 * @param The name of the attribute.
303 *
304 * @return The string of the attribute.
305 *
306 */
307
308 public String getAttribute( String name )
309 {
310 NamedNodeMap nodeMap = modelNode.getAttributes();
311 if( nodeMap != null )
312 {
313 Node attribute = nodeMap.getNamedItem(name);
314 if( attribute != null )
315 {
316 return attribute.getFirstChild().getNodeValue();
317 }
318 }
319
320 return "";
321 }
322
323 /**
324 * Sets the string value of the attribute.
325 *
326 * @param name The name of the attribute.
327 * @param value The value of the attribute.
328 *
329 */
330
331 public void setAttribute( String name, String value )
332 {
333 // state DOM modification
334 owner.setModified();
335
336 // retrieve and update attribute
337 NamedNodeMap nodeMap = modelNode.getAttributes();
338
339 Attr attribute = modelNode.getOwnerDocument().createAttribute(name);
340 attribute.setValue(value);
341
342 nodeMap.setNamedItem(attribute);
343 }
344
345
346 /* Node access. */
347
348
349 /**
350 * The parent of this node. All nodes, except the root ({@link ModelNode})
351 * node may have a parent. If a node has just been created and not yet added to the tree, or if
352 * it has been removed from the tree, this is null.
353 *
354 * @return The parent of this node.
355 *
356 */
357
358 public ModelNode getParentNode()
359 {
360 Node parentNode = modelNode.getParentNode();
361
362 if( parentNode != null )
363 {
364 return new XalanModelNode(owner, parentNode);
365 }
366
367 return null;
368 }
369
370 /**
371 * The first child of this node. If there is no such node, this returns null.
372 *
373 * @return The first child node.
374 *
375 */
376
377 public ModelNode getFirstChild()
378 {
379 Node node = modelNode.getFirstChild();
380
381 if( node != null )
382 {
383 return new XalanModelNode(owner, node);
384 }
385
386 return null;
387 }
388
389 /**
390 * The last child of this node. If there is no such node, this returns null.
391 *
392 * @return The last child node.
393 *
394 */
395
396 public ModelNode getLastChild()
397 {
398 Node node = modelNode.getLastChild();
399
400 if( node != null )
401 {
402 return new XalanModelNode(owner, node);
403 }
404
405 return null;
406 }
407
408 /**
409 * The node immediately preceding this node. If there is no such node,
410 * this returns null.
411 *
412 * @return The preceding sibling node.
413 *
414 */
415
416 public ModelNode getPreviousSibling()
417 {
418 Node node = modelNode.getPreviousSibling();
419
420 if( node != null )
421 {
422 return new XalanModelNode(owner, node);
423 }
424
425 return null;
426 }
427
428 /**
429 * The node immediately following this node. If there is no such node,
430 * this returns null.
431 *
432 * @return The following sibling node.
433 *
434 */
435
436 public ModelNode getNextSibling()
437 {
438 Node node = modelNode.getNextSibling();
439
440 if( node != null )
441 {
442 return new XalanModelNode(owner, node);
443 }
444
445 return null;
446 }
447
448 /**
449 * Returns a <code>List</code> of {@link ModelNode}'s using the path provided.
450 *
451 * @return A <code>List</code> of this nodes' children as {@link ModelNode}'s.
452 *
453 */
454
455 public List getChildNodes()
456 {
457 ArrayList xmlNodeList = new ArrayList();
458
459 Node tmpNode = modelNode.getFirstChild();
460
461 while (tmpNode != null)
462 {
463 xmlNodeList.add( new XalanModelNode(owner, tmpNode) );
464 tmpNode = tmpNode.getNextSibling();
465 }
466
467 return xmlNodeList;
468 }
469
470 /**
471 * Returns whether this node has any children.
472 *
473 * @return True if this node has children, false otherwise.
474 *
475 */
476
477 public boolean hasChildNodes()
478 {
479 return modelNode.hasChildNodes();
480 }
481
482
483 /* Node manipulation. */
484
485
486 /**
487 * Adds the node <code>newChild</code> to the end of the list of children of this node.
488 * If the <code>newChild</code> is already in the tree, it is first removed.
489 *
490 * @param newChild The node to add.
491 *
492 * @return The node added.
493 *
494 */
495
496 public ModelNode appendChild(ModelNode newChild)
497 {
498 // state DOM modification
499 owner.setModified();
500
501 // append node
502 Node childNode = ((XalanModelNode)newChild).getXmlNode();
503 Node node = modelNode.appendChild(childNode);
504 return new XalanModelNode(owner, node);
505 }
506
507 /**
508 * Inserts the node <code>newChild</code> before the existing child node <code>refChild</code>.
509 * If <code>refChild</code> is null, <code>newChild</code> is inserted at the end of the list
510 * of children. If the <code>newChild</code> is already in the tree, it is first removed.
511 *
512 * @param newChild The node to insert.
513 * @param refChild The reference node.
514 *
515 * @return The node inserted.
516 *
517 */
518
519 public ModelNode insertBefore(ModelNode newChild, ModelNode refChild)
520 {
521 // state DOM modification
522 owner.setModified();
523
524 // insert node
525 Node xNewChild = ((XalanModelNode)newChild).getXmlNode();
526 Node xRefChild = ((XalanModelNode)refChild).getXmlNode();
527
528 Node node = modelNode.insertBefore(xNewChild, xRefChild);
529 return new XalanModelNode(owner, node);
530 }
531
532 /**
533 * Replaces the child node <code>oldChild</code> with <code>newChild</code>, and returns
534 * the <code>oldChild</code> node. If the <code>newChild</code> is already in the tree,
535 * it is first removed.
536 *
537 * @param newChild The node to replace.
538 * @param oldChild The node being replaced.
539 *
540 * @return The node replaced.
541 *
542 */
543
544 public ModelNode replaceChild(ModelNode newChild, ModelNode oldChild)
545 {
546 // state DOM modification
547 owner.setModified();
548
549 // replaceNode
550 Node xNewChild = ((XalanModelNode)newChild).getXmlNode();
551 Node xOldChild = ((XalanModelNode)oldChild).getXmlNode();
552
553 Node node = modelNode.replaceChild(xNewChild, xOldChild);
554 return new XalanModelNode(owner, node);
555 }
556
557 /**
558 * Removes the child node indicated by <code>oldChild</code> from the list of children,
559 * and returns it.
560 *
561 * @param oldChild The node to remove.
562 *
563 * @return The removed node.
564 *
565 */
566
567 public ModelNode removeChild(ModelNode oldChild)
568 {
569 // state DOM modification
570 owner.setModified();
571
572 // remove node
573 Node xOldNode = ((XalanModelNode)oldChild).getXmlNode();
574 Node node = modelNode.removeChild(xOldNode);
575 return new XalanModelNode(owner, node);
576 }
577
578 /**
579 * Display the string value of the node.
580 *
581 */
582
583 public String toString()
584 {
585 StringBuffer buffer = new StringBuffer();
586
587 if (modelNode != null)
588 {
589 buffer.append("name=");
590 buffer.append(getNodeName());
591 buffer.append("; ");
592 }
593
594 buffer.append("value=" + modelValue);
595
596 if (modelNode != null)
597 {
598 buffer.append("; node=");
599 buffer.append(modelNode.toString());
600 }
601
602 return buffer.toString();
603 }
604 }
605