001: /*
002: * @(#)DOMNodeImpl.java 1.11 2000/08/16
003: *
004: */
005:
006: package org.w3c.tidy;
007:
008: import org.w3c.dom.DOMException;
009:
010: /**
011: *
012: * DOMNodeImpl
013: *
014: * (c) 1998-2000 (W3C) MIT, INRIA, Keio University
015: * See Tidy.java for the copyright notice.
016: * Derived from <a href="http://www.w3.org/People/Raggett/tidy">
017: * HTML Tidy Release 4 Aug 2000</a>
018: *
019: * @author Dave Raggett <dsr@w3.org>
020: * @author Andy Quick <ac.quick@sympatico.ca> (translation to Java)
021: * @version 1.4, 1999/09/04 DOM Support
022: * @version 1.5, 1999/10/23 Tidy Release 27 Sep 1999
023: * @version 1.6, 1999/11/01 Tidy Release 22 Oct 1999
024: * @version 1.7, 1999/12/06 Tidy Release 30 Nov 1999
025: * @version 1.8, 2000/01/22 Tidy Release 13 Jan 2000
026: * @version 1.9, 2000/06/03 Tidy Release 30 Apr 2000
027: * @version 1.10, 2000/07/22 Tidy Release 8 Jul 2000
028: * @version 1.11, 2000/08/16 Tidy Release 4 Aug 2000
029: */
030:
031: public class DOMNodeImpl implements org.w3c.dom.Node {
032:
033: protected Node adaptee;
034:
035: protected DOMNodeImpl(Node adaptee) {
036: this .adaptee = adaptee;
037: }
038:
039: /* --------------------- DOM ---------------------------- */
040:
041: /**
042: * @see org.w3c.dom.Node#getNodeValue
043: */
044: public String getNodeValue() throws DOMException {
045: String value = ""; //BAK 10/10/2000 replaced null
046: if (adaptee.type == Node.TextNode
047: || adaptee.type == Node.CDATATag
048: || adaptee.type == Node.CommentTag ||
049: // BEGIN RAVE MODIFICATIONS
050: adaptee.type == Node.AspTag ||
051: // END RAVE MODIFICATIONS
052: adaptee.type == Node.ProcInsTag) {
053:
054: if (adaptee.textarray != null
055: && adaptee.start < adaptee.end) {
056: value = Lexer.getString(adaptee.textarray,
057: adaptee.start, adaptee.end - adaptee.start);
058: }
059: }
060: return value;
061: }
062:
063: /**
064: * @see org.w3c.dom.Node#setNodeValue
065: */
066: public void setNodeValue(String nodeValue) throws DOMException {
067: if (adaptee.type == Node.TextNode
068: || adaptee.type == Node.CDATATag
069: ||
070: // BEGIN RAVE MODIFICATIONS
071: adaptee.type == Node.AspTag
072: ||
073: // END RAVE MODIFICATIONS
074: adaptee.type == Node.CommentTag
075: || adaptee.type == Node.ProcInsTag) {
076: byte[] textarray = Lexer.getBytes(nodeValue);
077: adaptee.textarray = textarray;
078: adaptee.start = 0;
079: adaptee.end = textarray.length;
080: }
081: }
082:
083: /**
084: * @see org.w3c.dom.Node#getNodeName
085: */
086: public String getNodeName() {
087: return adaptee.element;
088: }
089:
090: /**
091: * @see org.w3c.dom.Node#getNodeType
092: */
093: public short getNodeType() {
094: short result = -1;
095: switch (adaptee.type) {
096: case Node.RootNode:
097: result = org.w3c.dom.Node.DOCUMENT_NODE;
098: break;
099: case Node.DocTypeTag:
100: result = org.w3c.dom.Node.DOCUMENT_TYPE_NODE;
101: break;
102: case Node.CommentTag:
103: result = org.w3c.dom.Node.COMMENT_NODE;
104: break;
105: case Node.ProcInsTag:
106: result = org.w3c.dom.Node.PROCESSING_INSTRUCTION_NODE;
107: break;
108: case Node.TextNode:
109: result = org.w3c.dom.Node.TEXT_NODE;
110: break;
111: case Node.CDATATag:
112: result = org.w3c.dom.Node.CDATA_SECTION_NODE;
113: break;
114: case Node.StartTag:
115: case Node.StartEndTag:
116: result = org.w3c.dom.Node.ELEMENT_NODE;
117: break;
118: // BEGIN RAVE MODIFICATIONS
119: case Node.AspTag:
120: result = 115; // SPECIAL MARKER!! HACK!!
121: // END RAVE MODIFICATIONS
122: }
123: return result;
124: }
125:
126: /**
127: * @see org.w3c.dom.Node#getParentNode
128: */
129: public org.w3c.dom.Node getParentNode() {
130: if (adaptee.parent != null)
131: return adaptee.parent.getAdapter();
132: else
133: return null;
134: }
135:
136: /**
137: * @see org.w3c.dom.Node#getChildNodes
138: */
139: public org.w3c.dom.NodeList getChildNodes() {
140: return new DOMNodeListImpl(adaptee);
141: }
142:
143: /**
144: * @see org.w3c.dom.Node#getFirstChild
145: */
146: public org.w3c.dom.Node getFirstChild() {
147: if (adaptee.content != null)
148: return adaptee.content.getAdapter();
149: else
150: return null;
151: }
152:
153: /**
154: * @see org.w3c.dom.Node#getLastChild
155: */
156: public org.w3c.dom.Node getLastChild() {
157: if (adaptee.last != null)
158: return adaptee.last.getAdapter();
159: else
160: return null;
161: }
162:
163: /**
164: * @see org.w3c.dom.Node#getPreviousSibling
165: */
166: public org.w3c.dom.Node getPreviousSibling() {
167: if (adaptee.prev != null)
168: return adaptee.prev.getAdapter();
169: else
170: return null;
171: }
172:
173: /**
174: * @see org.w3c.dom.Node#getNextSibling
175: */
176: public org.w3c.dom.Node getNextSibling() {
177: if (adaptee.next != null)
178: return adaptee.next.getAdapter();
179: else
180: return null;
181: }
182:
183: /**
184: * @see org.w3c.dom.Node#getAttributes
185: */
186: public org.w3c.dom.NamedNodeMap getAttributes() {
187: return new DOMAttrMapImpl(adaptee.attributes);
188: }
189:
190: /**
191: * @see org.w3c.dom.Node#getOwnerDocument
192: */
193: public org.w3c.dom.Document getOwnerDocument() {
194: Node node;
195:
196: node = this .adaptee;
197: if (node != null && node.type == Node.RootNode)
198: return null;
199:
200: for (node = this .adaptee; node != null
201: && node.type != Node.RootNode; node = node.parent)
202: ;
203:
204: if (node != null)
205: return (org.w3c.dom.Document) node.getAdapter();
206: else
207: return null;
208: }
209:
210: /**
211: * @see org.w3c.dom.Node#insertBefore
212: */
213: public org.w3c.dom.Node insertBefore(org.w3c.dom.Node newChild,
214: org.w3c.dom.Node refChild) throws DOMException {
215: // TODO - handle newChild already in tree
216:
217: if (newChild == null)
218: return null;
219: if (!(newChild instanceof DOMNodeImpl)) {
220: throw new DOMExceptionImpl(DOMException.WRONG_DOCUMENT_ERR,
221: "newChild not instanceof DOMNodeImpl");
222: }
223: DOMNodeImpl newCh = (DOMNodeImpl) newChild;
224:
225: if (this .adaptee.type == Node.RootNode) {
226: if (newCh.adaptee.type != Node.DocTypeTag
227: && newCh.adaptee.type != Node.ProcInsTag) {
228: throw new DOMExceptionImpl(
229: DOMException.HIERARCHY_REQUEST_ERR,
230: "newChild cannot be a child of this node");
231: }
232: } else if (this .adaptee.type == Node.StartTag) {
233: if (newCh.adaptee.type != Node.StartTag
234: && newCh.adaptee.type != Node.StartEndTag
235: && newCh.adaptee.type != Node.CommentTag
236: && newCh.adaptee.type != Node.TextNode
237: && newCh.adaptee.type != Node.CDATATag) {
238: throw new DOMExceptionImpl(
239: DOMException.HIERARCHY_REQUEST_ERR,
240: "newChild cannot be a child of this node");
241: }
242: }
243: if (refChild == null) {
244: Node.insertNodeAtEnd(this .adaptee, newCh.adaptee);
245: if (this .adaptee.type == Node.StartEndTag) {
246: this .adaptee.setType(Node.StartTag);
247: }
248: } else {
249: Node ref = this .adaptee.content;
250: while (ref != null) {
251: if (ref.getAdapter() == refChild)
252: break;
253: ref = ref.next;
254: }
255: if (ref == null) {
256: throw new DOMExceptionImpl(DOMException.NOT_FOUND_ERR,
257: "refChild not found");
258: }
259: Node.insertNodeBeforeElement(ref, newCh.adaptee);
260: }
261: return newChild;
262: }
263:
264: /**
265: * @see org.w3c.dom.Node#replaceChild
266: */
267: public org.w3c.dom.Node replaceChild(org.w3c.dom.Node newChild,
268: org.w3c.dom.Node oldChild) throws DOMException {
269: // TODO - handle newChild already in tree
270:
271: if (newChild == null)
272: return null;
273: if (!(newChild instanceof DOMNodeImpl)) {
274: throw new DOMExceptionImpl(DOMException.WRONG_DOCUMENT_ERR,
275: "newChild not instanceof DOMNodeImpl");
276: }
277: DOMNodeImpl newCh = (DOMNodeImpl) newChild;
278:
279: if (this .adaptee.type == Node.RootNode) {
280: if (newCh.adaptee.type != Node.DocTypeTag
281: && newCh.adaptee.type != Node.ProcInsTag) {
282: throw new DOMExceptionImpl(
283: DOMException.HIERARCHY_REQUEST_ERR,
284: "newChild cannot be a child of this node");
285: }
286: } else if (this .adaptee.type == Node.StartTag) {
287: if (newCh.adaptee.type != Node.StartTag
288: && newCh.adaptee.type != Node.StartEndTag
289: && newCh.adaptee.type != Node.CommentTag
290: && newCh.adaptee.type != Node.TextNode
291: && newCh.adaptee.type != Node.CDATATag) {
292: throw new DOMExceptionImpl(
293: DOMException.HIERARCHY_REQUEST_ERR,
294: "newChild cannot be a child of this node");
295: }
296: }
297: if (oldChild == null) {
298: throw new DOMExceptionImpl(DOMException.NOT_FOUND_ERR,
299: "oldChild not found");
300: } else {
301: Node n;
302: Node ref = this .adaptee.content;
303: while (ref != null) {
304: if (ref.getAdapter() == oldChild)
305: break;
306: ref = ref.next;
307: }
308: if (ref == null) {
309: throw new DOMExceptionImpl(DOMException.NOT_FOUND_ERR,
310: "oldChild not found");
311: }
312: newCh.adaptee.next = ref.next;
313: newCh.adaptee.prev = ref.prev;
314: newCh.adaptee.last = ref.last;
315: newCh.adaptee.parent = ref.parent;
316: newCh.adaptee.content = ref.content;
317: if (ref.parent != null) {
318: if (ref.parent.content == ref)
319: ref.parent.content = newCh.adaptee;
320: if (ref.parent.last == ref)
321: ref.parent.last = newCh.adaptee;
322: }
323: if (ref.prev != null) {
324: ref.prev.next = newCh.adaptee;
325: }
326: if (ref.next != null) {
327: ref.next.prev = newCh.adaptee;
328: }
329: for (n = ref.content; n != null; n = n.next) {
330: if (n.parent == ref)
331: n.parent = newCh.adaptee;
332: }
333: }
334: return oldChild;
335: }
336:
337: /**
338: * @see org.w3c.dom.Node#removeChild
339: */
340: public org.w3c.dom.Node removeChild(org.w3c.dom.Node oldChild)
341: throws DOMException {
342: if (oldChild == null)
343: return null;
344:
345: Node ref = this .adaptee.content;
346: while (ref != null) {
347: if (ref.getAdapter() == oldChild)
348: break;
349: ref = ref.next;
350: }
351: if (ref == null) {
352: throw new DOMExceptionImpl(DOMException.NOT_FOUND_ERR,
353: "refChild not found");
354: }
355: Node.discardElement(ref);
356:
357: if (this .adaptee.content == null
358: && this .adaptee.type == Node.StartTag) {
359: this .adaptee.setType(Node.StartEndTag);
360: }
361:
362: return oldChild;
363: }
364:
365: /**
366: * @see org.w3c.dom.Node#appendChild
367: */
368: public org.w3c.dom.Node appendChild(org.w3c.dom.Node newChild)
369: throws DOMException {
370: // TODO - handle newChild already in tree
371:
372: if (newChild == null)
373: return null;
374: if (!(newChild instanceof DOMNodeImpl)) {
375: throw new DOMExceptionImpl(DOMException.WRONG_DOCUMENT_ERR,
376: "newChild not instanceof DOMNodeImpl");
377: }
378: DOMNodeImpl newCh = (DOMNodeImpl) newChild;
379:
380: if (this .adaptee.type == Node.RootNode) {
381: if (newCh.adaptee.type != Node.DocTypeTag
382: && newCh.adaptee.type != Node.ProcInsTag) {
383: throw new DOMExceptionImpl(
384: DOMException.HIERARCHY_REQUEST_ERR,
385: "newChild cannot be a child of this node");
386: }
387: } else if (this .adaptee.type == Node.StartTag) {
388: if (newCh.adaptee.type != Node.StartTag
389: && newCh.adaptee.type != Node.StartEndTag
390: && newCh.adaptee.type != Node.CommentTag
391: && newCh.adaptee.type != Node.TextNode
392: && newCh.adaptee.type != Node.CDATATag) {
393: throw new DOMExceptionImpl(
394: DOMException.HIERARCHY_REQUEST_ERR,
395: "newChild cannot be a child of this node");
396: }
397: }
398: Node.insertNodeAtEnd(this .adaptee, newCh.adaptee);
399:
400: if (this .adaptee.type == Node.StartEndTag) {
401: this .adaptee.setType(Node.StartTag);
402: }
403:
404: return newChild;
405: }
406:
407: /**
408: * @see org.w3c.dom.Node#hasChildNodes
409: */
410: public boolean hasChildNodes() {
411: return (adaptee.content != null);
412: }
413:
414: /**
415: * @see org.w3c.dom.Node#cloneNode
416: */
417: public org.w3c.dom.Node cloneNode(boolean deep) {
418: Node node = adaptee.cloneNode(deep);
419: node.parent = null;
420: return node.getAdapter();
421: }
422:
423: /**
424: * DOM2 - not implemented.
425: */
426: public void normalize() {
427: }
428:
429: /**
430: * DOM2 - not implemented.
431: */
432: public boolean supports(String feature, String version) {
433: return isSupported(feature, version);
434: }
435:
436: /**
437: * DOM2 - not implemented.
438: */
439: public String getNamespaceURI() {
440: return null;
441: }
442:
443: /**
444: * DOM2 - not implemented.
445: */
446: public String getPrefix() {
447: return null;
448: }
449:
450: /**
451: * DOM2 - not implemented.
452: */
453: public void setPrefix(String prefix) throws DOMException {
454: }
455:
456: /**
457: * DOM2 - not implemented.
458: */
459: public String getLocalName() {
460: return null;
461: }
462:
463: /**
464: * DOM2 - not implemented.
465: */
466: public boolean isSupported(String feature, String version) {
467: return false;
468: }
469:
470: /**
471: * DOM2 - @see org.w3c.dom.Node#hasAttributes
472: * contributed by dlp@users.sourceforge.net
473: */
474: public boolean hasAttributes() {
475: return adaptee.attributes != null;
476: }
477: }
|