1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55 package org.w3c.tidy;
56
57 import org.w3c.dom.DOMException;
58 import org.w3c.dom.UserDataHandler;
59
60
61 /**
62 * DOMNodeImpl.
63 * @author Dave Raggett <a href="mailto:dsr@w3.org">dsr@w3.org </a>
64 * @author Andy Quick <a href="mailto:ac.quick@sympatico.ca">ac.quick@sympatico.ca </a> (translation to Java)
65 * @author Fabrizio Giustina
66 * @version $Revision: 779 $ ($Author: fgiust $)
67 */
68 public class DOMNodeImpl implements org.w3c.dom.Node
69 {
70
71 /**
72 * Wrapped tidy node.
73 */
74 protected Node adaptee;
75
76 /**
77 * Intantiates a new DOM node.
78 * @param adaptee wrapped Tidy node
79 */
80 protected DOMNodeImpl(Node adaptee)
81 {
82 this.adaptee = adaptee;
83 }
84
85 /**
86 * @see org.w3c.dom.Node#getNodeValue
87 */
88 public String getNodeValue()
89 {
90 String value = "";
91 if (adaptee.type == Node.TEXT_NODE
92 || adaptee.type == Node.CDATA_TAG
93 || adaptee.type == Node.COMMENT_TAG
94 || adaptee.type == Node.PROC_INS_TAG)
95 {
96
97 if (adaptee.textarray != null && adaptee.start < adaptee.end)
98 {
99 value = TidyUtils.getString(adaptee.textarray, adaptee.start, adaptee.end - adaptee.start);
100 }
101 }
102 return value;
103 }
104
105 /**
106 * @see org.w3c.dom.Node#setNodeValue
107 */
108 public void setNodeValue(String nodeValue)
109 {
110 if (adaptee.type == Node.TEXT_NODE
111 || adaptee.type == Node.CDATA_TAG
112 || adaptee.type == Node.COMMENT_TAG
113 || adaptee.type == Node.PROC_INS_TAG)
114 {
115 byte[] textarray = TidyUtils.getBytes(nodeValue);
116 adaptee.textarray = textarray;
117 adaptee.start = 0;
118 adaptee.end = textarray.length;
119 }
120 }
121
122 /**
123 * @see org.w3c.dom.Node#getNodeName
124 */
125 public String getNodeName()
126 {
127 return adaptee.element;
128 }
129
130 /**
131 * @see org.w3c.dom.Node#getNodeType
132 */
133 public short getNodeType()
134 {
135 short result = -1;
136 switch (adaptee.type)
137 {
138 case Node.ROOT_NODE :
139 result = org.w3c.dom.Node.DOCUMENT_NODE;
140 break;
141 case Node.DOCTYPE_TAG :
142 result = org.w3c.dom.Node.DOCUMENT_TYPE_NODE;
143 break;
144 case Node.COMMENT_TAG :
145 result = org.w3c.dom.Node.COMMENT_NODE;
146 break;
147 case Node.PROC_INS_TAG :
148 result = org.w3c.dom.Node.PROCESSING_INSTRUCTION_NODE;
149 break;
150 case Node.TEXT_NODE :
151 result = org.w3c.dom.Node.TEXT_NODE;
152 break;
153 case Node.CDATA_TAG :
154 result = org.w3c.dom.Node.CDATA_SECTION_NODE;
155 break;
156 case Node.START_TAG :
157 case Node.START_END_TAG :
158 result = org.w3c.dom.Node.ELEMENT_NODE;
159 break;
160 }
161 return result;
162 }
163
164 /**
165 * @see org.w3c.dom.Node#getParentNode
166 */
167 public org.w3c.dom.Node getParentNode()
168 {
169
170 if (adaptee.parent != null)
171 {
172 return adaptee.parent.getAdapter();
173 }
174 return null;
175 }
176
177 /**
178 * @see org.w3c.dom.Node#getChildNodes
179 */
180 public org.w3c.dom.NodeList getChildNodes()
181 {
182 return new DOMNodeListImpl(adaptee);
183 }
184
185 /**
186 * @see org.w3c.dom.Node#getFirstChild
187 */
188 public org.w3c.dom.Node getFirstChild()
189 {
190 if (adaptee.content != null)
191 {
192 return adaptee.content.getAdapter();
193 }
194 return null;
195 }
196
197 /**
198 * @see org.w3c.dom.Node#getLastChild
199 */
200 public org.w3c.dom.Node getLastChild()
201 {
202 if (adaptee.last != null)
203 {
204 return adaptee.last.getAdapter();
205 }
206 return null;
207 }
208
209 /**
210 * @see org.w3c.dom.Node#getPreviousSibling
211 */
212 public org.w3c.dom.Node getPreviousSibling()
213 {
214 if (adaptee.prev != null)
215 {
216 return adaptee.prev.getAdapter();
217 }
218 return null;
219 }
220
221 /**
222 * @see org.w3c.dom.Node#getNextSibling
223 */
224 public org.w3c.dom.Node getNextSibling()
225 {
226 if (adaptee.next != null)
227 {
228 return adaptee.next.getAdapter();
229 }
230 return null;
231 }
232
233 /**
234 * @see org.w3c.dom.Node#getAttributes
235 */
236 public org.w3c.dom.NamedNodeMap getAttributes()
237 {
238 return new DOMAttrMapImpl(adaptee.attributes);
239 }
240
241 /**
242 * @see org.w3c.dom.Node#getOwnerDocument
243 */
244 public org.w3c.dom.Document getOwnerDocument()
245 {
246 Node node = this.adaptee;
247 if (node != null && node.type == Node.ROOT_NODE)
248 {
249 return null;
250 }
251
252 while (node != null && node.type != Node.ROOT_NODE)
253 {
254 node = node.parent;
255 }
256
257 if (node != null)
258 {
259 return (org.w3c.dom.Document) node.getAdapter();
260 }
261 return null;
262 }
263
264 /**
265 * @see org.w3c.dom.Node#insertBefore
266 */
267 public org.w3c.dom.Node insertBefore(org.w3c.dom.Node newChild, org.w3c.dom.Node refChild)
268 {
269
270
271 if (newChild == null)
272 {
273 return null;
274 }
275 if (!(newChild instanceof DOMNodeImpl))
276 {
277 throw new DOMException(DOMException.WRONG_DOCUMENT_ERR, "newChild not instanceof DOMNodeImpl");
278 }
279 DOMNodeImpl newCh = (DOMNodeImpl) newChild;
280
281 if (this.adaptee.type == Node.ROOT_NODE)
282 {
283 if (newCh.adaptee.type != Node.DOCTYPE_TAG && newCh.adaptee.type != Node.PROC_INS_TAG)
284 {
285 throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR, "newChild cannot be a child of this node");
286 }
287 }
288 else if (this.adaptee.type == Node.START_TAG)
289 {
290 if (newCh.adaptee.type != Node.START_TAG
291 && newCh.adaptee.type != Node.START_END_TAG
292 && newCh.adaptee.type != Node.COMMENT_TAG
293 && newCh.adaptee.type != Node.TEXT_NODE
294 && newCh.adaptee.type != Node.CDATA_TAG)
295 {
296 throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR, "newChild cannot be a child of this node");
297 }
298 }
299 if (refChild == null)
300 {
301 this.adaptee.insertNodeAtEnd(newCh.adaptee);
302 if (this.adaptee.type == Node.START_END_TAG)
303 {
304 this.adaptee.setType(Node.START_TAG);
305 }
306 }
307 else
308 {
309 Node ref = this.adaptee.content;
310 while (ref != null)
311 {
312 if (ref.getAdapter() == refChild)
313 {
314 break;
315 }
316 ref = ref.next;
317 }
318 if (ref == null)
319 {
320 throw new DOMException(DOMException.NOT_FOUND_ERR, "refChild not found");
321 }
322 Node.insertNodeBeforeElement(ref, newCh.adaptee);
323 }
324 return newChild;
325 }
326
327 /**
328 * @see org.w3c.dom.Node#replaceChild
329 */
330 public org.w3c.dom.Node replaceChild(org.w3c.dom.Node newChild, org.w3c.dom.Node oldChild)
331 {
332
333
334 if (newChild == null)
335 {
336 return null;
337 }
338 if (!(newChild instanceof DOMNodeImpl))
339 {
340 throw new DOMException(DOMException.WRONG_DOCUMENT_ERR, "newChild not instanceof DOMNodeImpl");
341 }
342 DOMNodeImpl newCh = (DOMNodeImpl) newChild;
343
344 if (this.adaptee.type == Node.ROOT_NODE)
345 {
346 if (newCh.adaptee.type != Node.DOCTYPE_TAG && newCh.adaptee.type != Node.PROC_INS_TAG)
347 {
348 throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR, "newChild cannot be a child of this node");
349 }
350 }
351 else if (this.adaptee.type == Node.START_TAG)
352 {
353 if (newCh.adaptee.type != Node.START_TAG
354 && newCh.adaptee.type != Node.START_END_TAG
355 && newCh.adaptee.type != Node.COMMENT_TAG
356 && newCh.adaptee.type != Node.TEXT_NODE
357 && newCh.adaptee.type != Node.CDATA_TAG)
358 {
359 throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR, "newChild cannot be a child of this node");
360 }
361 }
362 if (oldChild == null)
363 {
364 throw new DOMException(DOMException.NOT_FOUND_ERR, "oldChild not found");
365 }
366
367 Node n;
368 Node ref = this.adaptee.content;
369 while (ref != null)
370 {
371 if (ref.getAdapter() == oldChild)
372 {
373 break;
374 }
375 ref = ref.next;
376 }
377 if (ref == null)
378 {
379 throw new DOMException(DOMException.NOT_FOUND_ERR, "oldChild not found");
380 }
381 newCh.adaptee.next = ref.next;
382 newCh.adaptee.prev = ref.prev;
383 newCh.adaptee.last = ref.last;
384 newCh.adaptee.parent = ref.parent;
385 newCh.adaptee.content = ref.content;
386 if (ref.parent != null)
387 {
388 if (ref.parent.content == ref)
389 {
390 ref.parent.content = newCh.adaptee;
391 }
392 if (ref.parent.last == ref)
393 {
394 ref.parent.last = newCh.adaptee;
395 }
396 }
397 if (ref.prev != null)
398 {
399 ref.prev.next = newCh.adaptee;
400 }
401 if (ref.next != null)
402 {
403 ref.next.prev = newCh.adaptee;
404 }
405 for (n = ref.content; n != null; n = n.next)
406 {
407 if (n.parent == ref)
408 {
409 n.parent = newCh.adaptee;
410 }
411 }
412
413 return oldChild;
414 }
415
416 /**
417 * @see org.w3c.dom.Node#removeChild
418 */
419 public org.w3c.dom.Node removeChild(org.w3c.dom.Node oldChild)
420 {
421 if (oldChild == null)
422 {
423 return null;
424 }
425
426 Node ref = this.adaptee.content;
427 while (ref != null)
428 {
429 if (ref.getAdapter() == oldChild)
430 {
431 break;
432 }
433 ref = ref.next;
434 }
435 if (ref == null)
436 {
437 throw new DOMException(DOMException.NOT_FOUND_ERR, "refChild not found");
438 }
439 Node.discardElement(ref);
440
441 if (this.adaptee.content == null && this.adaptee.type == Node.START_TAG)
442 {
443 this.adaptee.setType(Node.START_END_TAG);
444 }
445
446 return oldChild;
447 }
448
449 /**
450 * @see org.w3c.dom.Node#appendChild
451 */
452 public org.w3c.dom.Node appendChild(org.w3c.dom.Node newChild)
453 {
454
455
456 if (newChild == null)
457 {
458 return null;
459 }
460 if (!(newChild instanceof DOMNodeImpl))
461 {
462 throw new DOMException(DOMException.WRONG_DOCUMENT_ERR, "newChild not instanceof DOMNodeImpl");
463 }
464 DOMNodeImpl newCh = (DOMNodeImpl) newChild;
465
466 if (this.adaptee.type == Node.ROOT_NODE)
467 {
468 if (newCh.adaptee.type != Node.DOCTYPE_TAG && newCh.adaptee.type != Node.PROC_INS_TAG)
469 {
470 throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR, "newChild cannot be a child of this node");
471 }
472 }
473 else if (this.adaptee.type == Node.START_TAG)
474 {
475 if (newCh.adaptee.type != Node.START_TAG
476 && newCh.adaptee.type != Node.START_END_TAG
477 && newCh.adaptee.type != Node.COMMENT_TAG
478 && newCh.adaptee.type != Node.TEXT_NODE
479 && newCh.adaptee.type != Node.CDATA_TAG)
480 {
481 throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR, "newChild cannot be a child of this node");
482 }
483 }
484 this.adaptee.insertNodeAtEnd(newCh.adaptee);
485
486 if (this.adaptee.type == Node.START_END_TAG)
487 {
488 this.adaptee.setType(Node.START_TAG);
489 }
490
491 return newChild;
492 }
493
494 /**
495 * @see org.w3c.dom.Node#hasChildNodes
496 */
497 public boolean hasChildNodes()
498 {
499 return (adaptee.content != null);
500 }
501
502 /**
503 * @see org.w3c.dom.Node#cloneNode(boolean)
504 */
505 public org.w3c.dom.Node cloneNode(boolean deep)
506 {
507 Node node = adaptee.cloneNode(deep);
508 node.parent = null;
509 return node.getAdapter();
510 }
511
512 /**
513 * Do nothing: text nodes in html documents are important and jtidy already removes useless text during parsing.
514 * @see org.w3c.dom.Node#normalize()
515 */
516 public void normalize()
517 {
518
519 }
520
521 /**
522 * DOM2 - not implemented.
523 * @see #isSupported(java.lang.String, java.lang.String)
524 */
525 public boolean supports(String feature, String version)
526 {
527 return isSupported(feature, version);
528 }
529
530 /**
531 * @see org.w3c.dom.Node#getNamespaceURI()
532 */
533 public String getNamespaceURI()
534 {
535 return null;
536 }
537
538 /**
539 * @see org.w3c.dom.Node#getPrefix()
540 */
541 public String getPrefix()
542 {
543 return null;
544 }
545
546 /**
547 * @see org.w3c.dom.Node#setPrefix(java.lang.String)
548 */
549 public void setPrefix(String prefix) throws DOMException
550 {
551
552
553
554 }
555
556 /**
557 * @see org.w3c.dom.Node#getLocalName()
558 */
559 public String getLocalName()
560 {
561 return getNodeName();
562 }
563
564 /**
565 * @see org.w3c.dom.Node#isSupported(java.lang.String, java.lang.String)
566 */
567 public boolean isSupported(String feature, String version)
568 {
569 return false;
570 }
571
572 /**
573 * @see org.w3c.dom.Node#hasAttributes
574 */
575 public boolean hasAttributes()
576 {
577
578 return this.adaptee.attributes != null;
579 }
580
581 /**
582 * @todo DOM level 3 compareDocumentPosition() Not implemented.
583 * @see org.w3c.dom.Node#compareDocumentPosition(org.w3c.dom.Node)
584 */
585 public short compareDocumentPosition(org.w3c.dom.Node other) throws DOMException
586 {
587 throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "DOM method not supported");
588 }
589
590 /**
591 * @todo DOM level 3 getBaseURI() Not implemented. Returns null.
592 * @see org.w3c.dom.Node#getBaseURI()
593 */
594 public String getBaseURI()
595 {
596 return null;
597 }
598
599 /**
600 * @todo DOM level 3 getFeature() Not implemented. Returns null.
601 * @see org.w3c.dom.Node#getFeature(java.lang.String, java.lang.String)
602 */
603 public Object getFeature(String feature, String version)
604 {
605 return null;
606 }
607
608 /**
609 * @todo DOM level 3 getTextContent() Not implemented. Returns null.
610 * @see org.w3c.dom.Node#getTextContent()
611 */
612 public String getTextContent() throws DOMException
613 {
614 return null;
615 }
616
617 /**
618 * @todo DOM level 3 getUserData() Not implemented. Returns null.
619 * @see org.w3c.dom.Node#getUserData(java.lang.String)
620 */
621 public Object getUserData(String key)
622 {
623 return null;
624 }
625
626 /**
627 * @see org.w3c.dom.Node#isDefaultNamespace(java.lang.String)
628 */
629 public boolean isDefaultNamespace(String namespaceURI)
630 {
631 return false;
632 }
633
634 /**
635 * @todo DOM level 3 isEqualNode() Not implemented. Returns false.
636 * @see org.w3c.dom.Node#isEqualNode(org.w3c.dom.Node)
637 */
638 public boolean isEqualNode(org.w3c.dom.Node arg)
639 {
640 return false;
641 }
642
643 /**
644 * @todo DOM level 3 isSameNode() Not implemented. Returns false.
645 * @see org.w3c.dom.Node#isSameNode(org.w3c.dom.Node)
646 */
647 public boolean isSameNode(org.w3c.dom.Node other)
648 {
649 return false;
650 }
651
652 /**
653 * @see org.w3c.dom.Node#lookupNamespaceURI(java.lang.String)
654 */
655 public String lookupNamespaceURI(String prefix)
656 {
657 return null;
658 }
659
660 /**
661 * @see org.w3c.dom.Node#lookupPrefix(java.lang.String)
662 */
663 public String lookupPrefix(String namespaceURI)
664 {
665 return null;
666 }
667
668 /**
669 * @todo DOM level 3 setTextContent() Not implemented. Throws NO_MODIFICATION_ALLOWED_ERR
670 * @see org.w3c.dom.Node#setTextContent(java.lang.String)
671 */
672 public void setTextContent(String textContent) throws DOMException
673 {
674 throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, "Node is read only");
675 }
676
677 /**
678 * @todo DOM level 3 setUserData() Not implemented. Returns null.
679 * @see org.w3c.dom.Node#setUserData(java.lang.String, java.lang.Object, org.w3c.dom.UserDataHandler)
680 */
681 public Object setUserData(String key, Object data, UserDataHandler handler)
682 {
683 return null;
684 }
685 }