KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > ozoneDB > xml > dom > html > HTMLDocumentImpl


1 /**
2  * org/ozone-db/xml/dom/html/HTMLDocumentImpl.java
3  *
4  * The contents of this file are subject to the OpenXML Public
5  * License Version 1.0; you may not use this file except in compliance
6  * with the License. You may obtain a copy of the License at
7  * http://www.openxml.org/license.html
8  *
9  * THIS SOFTWARE IS DISTRIBUTED ON AN "AS IS" BASIS WITHOUT WARRANTY
10  * OF ANY KIND, EITHER EXPRESSED OR IMPLIED. THE INITIAL DEVELOPER
11  * AND ALL CONTRIBUTORS SHALL NOT BE LIABLE FOR ANY DAMAGES AS A
12  * RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
13  * DERIVATIVES. SEE THE LICENSE FOR THE SPECIFIC LANGUAGE GOVERNING
14  * RIGHTS AND LIMITATIONS UNDER THE LICENSE.
15  *
16  * The Initial Developer of this code under the License is Assaf Arkin.
17  * Portions created by Assaf Arkin are Copyright (C) 1998, 1999.
18  * All Rights Reserved.
19  */

20
21 package org.ozoneDB.xml.dom.html;
22
23 import org.ozoneDB.xml.dom.DOMExceptionImpl;
24 import org.ozoneDB.xml.dom.DocumentImpl;
25 import org.ozoneDB.xml.dom.NodeImpl;
26 import org.w3c.dom.*;
27 import org.w3c.dom.html.*;
28
29 import java.io.StringWriter JavaDoc;
30 import java.lang.reflect.Constructor JavaDoc;
31 import java.util.Hashtable JavaDoc;
32
33
34 /**
35  * Implements an HTML document. Provides access to the top level element in the
36  * document, its body and title.
37  * <P>
38  * Several methods create new nodes of all basic types (comment, text, element,
39  * etc.). These methods create new nodes but do not place them in the document
40  * tree. The nodes may be placed in the document tree using {@link
41  * org.w3c.dom.Node#appendChild} or {@link org.w3c.dom.Node#insertBefore}, or
42  * they may be placed in some other document tree.
43  * <P>
44  * Note: &lt;FRAMESET&gt; documents are not supported at the moment, neither
45  * are direct document writing ({@link #open}, {@link #write}) and HTTP attribute
46  * methods ({@link #getURL}, {@link #getCookie}).
47  *
48  *
49  * @version $Revision: 1.2 $ $Date: 2003/11/20 23:18:42 $
50  * @author <a HREF="mailto:arkin@trendline.co.il">Assaf Arkin</a>
51  * @see org.w3c.dom.html.HTMLDocument
52  * @see org.ozoneDB.xml.XMLDocument
53  */

54 public final class HTMLDocumentImpl extends DocumentImpl implements HTMLDocument {
55
56
57     public synchronized Element getDocumentElement() {
58         Node html;
59         Node child;
60         Node next;
61
62         // The document element is the top-level HTML element of the HTML
63
// document. Only this element should exist at the top level.
64
// If the HTML element is found, all other elements that might
65
// precede it are placed inside the HTML element.
66
html = getFirstChild();
67         while (html != null) {
68             if (html instanceof HTMLHtmlElement) {
69                 synchronized (html) {
70                     child = getFirstChild();
71                     while (child != null && child != html) {
72                         next = child.getNextSibling();
73                         html.appendChild( child );
74                         child = next;
75                     }
76                 }
77                 return (HTMLElement)html;
78             }
79             html = html.getNextSibling();
80         }
81
82         // HTML element must exist. Create a new element and dump the
83
// entire contents of the document into it in the same order as
84
// they appear now.
85
html = new HTMLHtmlElementImpl( (HTMLDocumentImpl)getOwnerDocument(), "HTML" );
86         child = getFirstChild();
87         while (child != null) {
88             next = child.getNextSibling();
89             html.appendChild( child );
90             child = next;
91         }
92         appendChild( html );
93         return (HTMLElement)html;
94     }
95
96
97     /**
98      * Obtains the &lt;HEAD&gt; element in the document, creating one if does
99      * not exist before. The &lt;HEAD&gt; element is the first element in the
100      * &lt;HTML&gt; in the document. The &lt;HTML&gt; element is obtained by
101      * calling {@link #getDocumentElement}. If the element does not exist, one
102      * is created.
103      * <P>
104      * Called by {@link #getTitle}, {@link #setTitle}, {@link #getBody} and
105      * {@link #setBody} to assure the document has the &lt;HEAD&gt; element
106      * correctly placed.
107      *
108      * @return The &lt;HEAD&gt; element
109      */

110     public synchronized HTMLElement getHead() {
111         Node head;
112         Node html;
113         Node child;
114         Node next;
115
116         // Call getDocumentElement() to get the HTML element that is also the
117
// top-level element in the document. Get the first element in the
118
// document that is called HEAD. Work with that.
119
html = getDocumentElement();
120         synchronized (html) {
121             head = html.getFirstChild();
122             while (head != null && !(head instanceof HTMLHeadElement)) {
123                 head = head.getNextSibling();
124             }
125             // HEAD exists but might not be first element in HTML: make sure
126
// it is and return it.
127
if (head != null) {
128                 synchronized (head) {
129                     child = html.getFirstChild();
130                     while (child != null && child != head) {
131                         next = child.getNextSibling();
132                         head.insertBefore( child, head.getFirstChild() );
133                         child = next;
134                     }
135                 }
136                 return (HTMLElement)head;
137             }
138
139             // Head does not exist, create a new one, place it at the top of the
140
// HTML element and return it.
141
head = new HTMLHeadElementImpl( (HTMLDocumentImpl)getOwnerDocument(), "HEAD" );
142             html.insertBefore( head, html.getFirstChild() );
143         }
144         return (HTMLElement)head;
145     }
146
147
148     public synchronized String JavaDoc getTitle() {
149         HTMLElement head;
150         Node title;
151
152         // Get the HEAD element and look for the TITLE element within.
153
// When found, make sure the TITLE is a direct child of HEAD,
154
// and return the title's text (the Text node contained within).
155
head = getHead();
156         title = head.getElementsByTagName( "TITLE" ).item( 0 );
157         if (title != null) {
158             if (title.getParentNode() != head) {
159                 head.appendChild( title );
160             }
161             return ((HTMLTitleElement)title).getText();
162         }
163         // No TITLE found, return an empty string.
164
return "";
165     }
166
167
168     public synchronized void setTitle( String JavaDoc newTitle ) {
169         HTMLElement head;
170         Node title;
171
172         // Get the HEAD element and look for the TITLE element within.
173
// When found, make sure the TITLE is a direct child of HEAD,
174
// and set the title's text (the Text node contained within).
175
head = getHead();
176         title = head.getElementsByTagName( "TITLE" ).item( 0 );
177         if (title != null) {
178             if (title.getParentNode() != head) {
179                 head.appendChild( title );
180             }
181             ((HTMLTitleElement)title).setText( newTitle );
182         } else {
183             // No TITLE found, create a new element and place it at the end
184
// of the HEAD element.
185
title = new HTMLTitleElementImpl( (HTMLDocumentImpl)getOwnerDocument(), "TITLE" );
186             head.appendChild( title );
187         }
188     }
189
190
191     public synchronized HTMLElement getBody() {
192         Node html;
193         Node head;
194         Node body;
195         Node child;
196         Node next;
197
198         // Call getDocumentElement() to get the HTML element that is also the
199
// top-level element in the document. Get the first element in the
200
// document that is called BODY. Work with that.
201
html = getDocumentElement();
202         head = getHead();
203         synchronized (html) {
204             body = head.getNextSibling();
205             while (body != null && !(body instanceof HTMLBodyElement)) {
206                 body = body.getNextSibling();
207             }
208             // If BODY was not found, try looking for FRAMESET instead.
209
if (body == null) {
210                 body = head.getNextSibling();
211                 while (body != null && !(body instanceof HTMLFrameSetElement)) {
212                     body = body.getNextSibling();
213                 }
214             }
215
216             // BODY/FRAMESET exists but might not be second element in HTML
217
// (after HEAD): make sure it is and return it.
218
if (body != null) {
219                 synchronized (body) {
220                     child = head.getNextSibling();
221                     while (child != null && child != body) {
222                         next = child.getNextSibling();
223                         body.insertBefore( child, body.getFirstChild() );
224                         child = next;
225                     }
226                 }
227                 return (HTMLElement)body;
228             }
229
230             // BODY does not exist, create a new one, place it in the HTML element
231
// right after the HEAD and return it.
232
body = new HTMLBodyElementImpl( (HTMLDocumentImpl)getOwnerDocument(), "BODY" );
233             html.appendChild( body );
234         }
235         return (HTMLElement)body;
236     }
237
238
239     public synchronized void setBody( HTMLElement newBody ) {
240         Node html;
241         Node body;
242         Node head;
243         Node child;
244
245         synchronized (newBody) {
246             // Call getDocumentElement() to get the HTML element that is also the
247
// top-level element in the document. Get the first element in the
248
// document that is called BODY. Work with that.
249
html = getDocumentElement();
250             head = getHead();
251             synchronized (html) {
252                 body = this.getElementsByTagName( "BODY" ).item( 0 );
253                 // BODY exists but might not follow HEAD in HTML. If not,
254
// make it so and replce it. Start with the HEAD and make
255
// sure the BODY is the first element after the HEAD.
256
if (body != null) {
257                     synchronized (body) {
258                         child = head;
259                         while (child != null) {
260                             if (child instanceof Element) {
261                                 if (child != body) {
262                                     html.insertBefore( newBody, child );
263                                 } else {
264                                     html.replaceChild( newBody, body );
265                                 }
266                                 return;
267                             }
268                             child = child.getNextSibling();
269                         }
270                         html.appendChild( newBody );
271                     }
272                     return;
273                 }
274                 // BODY does not exist, place it in the HTML element
275
// right after the HEAD.
276
html.appendChild( newBody );
277             }
278         }
279     }
280
281
282     public Element getElementById( String JavaDoc elementId ) {
283         return getElementById( elementId, this );
284     }
285
286
287     public NodeList getElementsByName( String JavaDoc elementName ) {
288         return new HTMLElementListImpl( this, "name" );
289     }
290
291
292     public Element createElement( String JavaDoc tagName ) throws DOMException {
293         Class JavaDoc elemClass;
294         Constructor JavaDoc cnst;
295
296         // First, make sure tag name is all upper case, next get the associated
297
// element class. If no class is found, generate a generic HTML element.
298
// Do so also if an unexpected exception occurs.
299
tagName = tagName.toUpperCase();
300         elemClass = (Class JavaDoc)_elementTypesHTML.get( tagName );
301         if (elemClass != null) {
302             // Get the constructor for the element. The signature specifies an
303
// owner document and a tag name. Use the constructor to instantiate
304
// a new object and return it.
305
try {
306                 cnst = elemClass.getConstructor( _elemClassSigHTML );
307                 return (Element)cnst.newInstance( new Object JavaDoc[] {this, tagName} );
308             } catch (Exception JavaDoc except) {
309                 Throwable JavaDoc thrw;
310
311                 if (except instanceof java.lang.reflect.InvocationTargetException JavaDoc) {
312                     thrw = ((java.lang.reflect.InvocationTargetException JavaDoc)except).getTargetException();
313                 } else {
314                     thrw = except;
315                 }
316                 System.out.println( "Exception " + thrw.getClass().getName() );
317                 System.out.println( thrw.getMessage() );
318
319                 throw new IllegalStateException JavaDoc( "Tag '" + tagName
320                         + "' associated with an Element class that failed to construct." );
321             }
322         }
323         return new HTMLElementImpl( this, tagName );
324     }
325
326
327     public String JavaDoc getReferrer() {
328         // Information not available on server side.
329
return null;
330     }
331
332
333     public String JavaDoc getDomain() {
334         // Information not available on server side.
335
return null;
336     }
337
338
339     public String JavaDoc getURL() {
340         // Information not available on server side.
341
return null;
342     }
343
344
345     public String JavaDoc getCookie() {
346         // Information not available on server side.
347
return null;
348     }
349
350
351     public void setCookie( String JavaDoc cookie ) {
352     // Information not available on server side.
353
}
354
355
356     public HTMLCollection getImages() {
357         // For more information see HTMLCollection#collectionMatch
358
if (_images == null) {
359             _images = new HTMLCollectionImpl( getBody(), HTMLCollectionImpl.IMAGE );
360         }
361         return _images;
362     }
363
364
365     public HTMLCollection getApplets() {
366         // For more information see HTMLCollection#collectionMatch
367
if (_applets == null) {
368             _applets = new HTMLCollectionImpl( getBody(), HTMLCollectionImpl.APPLET );
369         }
370         return _applets;
371     }
372
373
374     public HTMLCollection getLinks() {
375         // For more information see HTMLCollection#collectionMatch
376
if (_links == null) {
377             _links = new HTMLCollectionImpl( getBody(), HTMLCollectionImpl.LINK );
378         }
379         return _links;
380     }
381
382
383     public HTMLCollection getForms() {
384         // For more information see HTMLCollection#collectionMatch
385
if (_forms == null) {
386             _forms = new HTMLCollectionImpl( getBody(), HTMLCollectionImpl.FORM );
387         }
388         return _forms;
389     }
390
391
392     public HTMLCollection getAnchors() {
393         // For more information see HTMLCollection#collectionMatch
394
if (_anchors == null) {
395             _anchors = new HTMLCollectionImpl( getBody(), HTMLCollectionImpl.ANCHOR );
396         }
397         return _anchors;
398     }
399
400
401     public void open() {
402         // When called an in-memory is prepared. The document tree is still
403
// accessible the old way, until this writer is closed.
404
if (_writer == null) {
405             _writer = new StringWriter JavaDoc();
406         }
407     }
408
409
410     public void close() {
411         // ! NOT IMPLEMENTED, REQUIRES PARSER !
412
if (_writer != null) {
413             _writer = null;
414         }
415     }
416
417
418     public void write( String JavaDoc text ) {
419         // Write a string into the in-memory writer.
420
if (_writer != null) {
421             _writer.write( text );
422         }
423     }
424
425
426     public void writeln( String JavaDoc text ) {
427         // Write a line into the in-memory writer.
428
if (_writer != null) {
429             _writer.write( text + "\n" );
430         }
431     }
432
433
434     public Object JavaDoc clone() {
435         HTMLDocumentImpl clone;
436
437         clone = new HTMLDocumentImpl();
438         cloneInto( clone, true );
439         return clone;
440     }
441
442
443     public Node cloneNode( boolean deep ) {
444         HTMLDocumentImpl clone;
445
446         clone = new HTMLDocumentImpl();
447         cloneInto( clone, deep );
448         return clone;
449     }
450
451
452     protected Node castNewChild( Node newChild ) throws DOMException {
453         // Same method appears in HTMLElementImpl and HTMLDocumentImpl.
454

455         if (newChild == null) {
456             throw new DOMExceptionImpl( DOMException.HIERARCHY_REQUEST_ERR, "Child reference is null." );
457         }
458         if (!(newChild instanceof NodeImpl)) {
459             throw new DOMExceptionImpl( DOMException.HIERARCHY_REQUEST_ERR,
460                     "Child is not a compatible type for this node." );
461         }
462
463         // newChild must be HTMLElement, Text, Comment, DocumentFragment or
464
// ProcessingInstruction. CDATASection and EntityReference not supported
465
// in HTML documents.
466
if (!(newChild instanceof HTMLElementImpl || newChild instanceof Comment || newChild instanceof Text
467                 || newChild instanceof DocumentFragment || newChild instanceof ProcessingInstruction)) {
468             throw new DOMExceptionImpl( DOMException.HIERARCHY_REQUEST_ERR,
469                     "Child is not a compatible type for this node." );
470         }
471         return (NodeImpl)newChild;
472     }
473
474
475     /**
476      * Recursive method retreives an element by its <code>id</code> attribute.
477      * Called by {@link #getElementById(String)}.
478      *
479      * @param elementId The <code>id</code> value to look for
480      * @return The node in which to look for
481      */

482     private Element getElementById( String JavaDoc elementId, Node node ) {
483         Node child;
484         Element result;
485
486         child = node.getFirstChild();
487         while (child != null) {
488             if (child instanceof Element) {
489                 if (elementId.equals( ((Element)child).getAttribute( "id" ) )) {
490                     return (Element)child;
491                 }
492                 result = getElementById( elementId, child );
493                 if (result != null) {
494                     return result;
495                 }
496             }
497             child = child.getNextSibling();
498         }
499         return null;
500     }
501
502
503     /**
504      * Called by the constructor to populate the element types list (see {@link
505      * #_elementTypesHTML}). Will be called multiple times but populate the list
506      * only the first time. Replacement for static constructor due to unknown
507      * problem with the static constructor.
508      */

509     private static void populateElementTypes() {
510         if (_elementTypesHTML != null) {
511             return;
512         }
513         _elementTypesHTML = new Hashtable JavaDoc( 63 );
514         _elementTypesHTML.put( "A", HTMLAnchorElementImpl.class );
515         _elementTypesHTML.put( "APPLET", HTMLAppletElementImpl.class );
516         _elementTypesHTML.put( "AREA", HTMLAreaElementImpl.class );
517         _elementTypesHTML.put( "BASE", HTMLBaseElementImpl.class );
518         _elementTypesHTML.put( "BASEFONT", HTMLBaseFontElementImpl.class );
519         _elementTypesHTML.put( "BLOCKQUOTE", HTMLBlockquoteElementImpl.class );
520         _elementTypesHTML.put( "BODY", HTMLBodyElementImpl.class );
521         _elementTypesHTML.put( "BR", HTMLBRElementImpl.class );
522         _elementTypesHTML.put( "BUTTON", HTMLButtonElementImpl.class );
523         _elementTypesHTML.put( "DEL", HTMLModElementImpl.class );
524         _elementTypesHTML.put( "DIR", HTMLDirectoryElementImpl.class );
525         _elementTypesHTML.put( "DIV", HTMLDivElementImpl.class );
526         _elementTypesHTML.put( "DL", HTMLDListElementImpl.class );
527         _elementTypesHTML.put( "FIELDSET", HTMLFieldSetElementImpl.class );
528         _elementTypesHTML.put( "FONT", HTMLFontElementImpl.class );
529         _elementTypesHTML.put( "FORM", HTMLFormElementImpl.class );
530         _elementTypesHTML.put( "FRAME", HTMLFrameElementImpl.class );
531         _elementTypesHTML.put( "FRAMESET", HTMLFrameSetElementImpl.class );
532         _elementTypesHTML.put( "HEAD", HTMLHeadElementImpl.class );
533         _elementTypesHTML.put( "H1", HTMLHeadingElementImpl.class );
534         _elementTypesHTML.put( "H2", HTMLHeadingElementImpl.class );
535         _elementTypesHTML.put( "H3", HTMLHeadingElementImpl.class );
536         _elementTypesHTML.put( "H4", HTMLHeadingElementImpl.class );
537         _elementTypesHTML.put( "H5", HTMLHeadingElementImpl.class );
538         _elementTypesHTML.put( "H6", HTMLHeadingElementImpl.class );
539         _elementTypesHTML.put( "HR", HTMLHRElementImpl.class );
540         _elementTypesHTML.put( "HTML", HTMLHtmlElementImpl.class );
541         _elementTypesHTML.put( "IFRAME", HTMLIFrameElementImpl.class );
542         _elementTypesHTML.put( "IMG", HTMLImageElementImpl.class );
543         _elementTypesHTML.put( "INPUT", HTMLInputElementImpl.class );
544         _elementTypesHTML.put( "INS", HTMLModElementImpl.class );
545         _elementTypesHTML.put( "ISINDEX", HTMLIsIndexElementImpl.class );
546         _elementTypesHTML.put( "LABEL", HTMLLabelElementImpl.class );
547         _elementTypesHTML.put( "LEGEND", HTMLLegendElementImpl.class );
548         _elementTypesHTML.put( "LI", HTMLLIElementImpl.class );
549         _elementTypesHTML.put( "LINK", HTMLLinkElementImpl.class );
550         _elementTypesHTML.put( "MAP", HTMLMapElementImpl.class );
551         _elementTypesHTML.put( "MENU", HTMLMenuElementImpl.class );
552         _elementTypesHTML.put( "META", HTMLMetaElementImpl.class );
553         _elementTypesHTML.put( "OBJECT", HTMLObjectElementImpl.class );
554         _elementTypesHTML.put( "OL", HTMLOListElementImpl.class );
555         _elementTypesHTML.put( "OPTGROUP", HTMLOptGroupElementImpl.class );
556         _elementTypesHTML.put( "OPTION", HTMLOptionElementImpl.class );
557         _elementTypesHTML.put( "P", HTMLParagraphElementImpl.class );
558         _elementTypesHTML.put( "PARAM", HTMLParamElementImpl.class );
559         _elementTypesHTML.put( "PRE", HTMLPreElementImpl.class );
560         _elementTypesHTML.put( "Q", HTMLQuoteElementImpl.class );
561         _elementTypesHTML.put( "SCRIPT", HTMLScriptElementImpl.class );
562         _elementTypesHTML.put( "SELECT", HTMLSelectElementImpl.class );
563         _elementTypesHTML.put( "STYLE", HTMLStyleElementImpl.class );
564         _elementTypesHTML.put( "TABLE", HTMLTableElementImpl.class );
565         _elementTypesHTML.put( "CAPTION", HTMLTableCaptionElementImpl.class );
566         _elementTypesHTML.put( "TD", HTMLTableCellElementImpl.class );
567         _elementTypesHTML.put( "COL", HTMLTableColElementImpl.class );
568         _elementTypesHTML.put( "COLGROUP", HTMLTableColElementImpl.class );
569         _elementTypesHTML.put( "TR", HTMLTableRowElementImpl.class );
570         _elementTypesHTML.put( "TBODY", HTMLTableSectionElementImpl.class );
571         _elementTypesHTML.put( "THEAD", HTMLTableSectionElementImpl.class );
572         _elementTypesHTML.put( "TFOOT", HTMLTableSectionElementImpl.class );
573         _elementTypesHTML.put( "TEXTAREA", HTMLTextAreaElementImpl.class );
574         _elementTypesHTML.put( "TITLE", HTMLTitleElementImpl.class );
575         _elementTypesHTML.put( "UL", HTMLUListElementImpl.class );
576     }
577
578
579     /**
580      */

581     public HTMLDocumentImpl() {
582         super();
583         populateElementTypes();
584     }
585
586
587     /**
588      * Holds {@link HTMLCollectionImpl} object with live collection of all
589      * anchors in document. This reference is on demand only once.
590      */

591     private HTMLCollectionImpl _anchors;
592
593
594     /**
595      * Holds {@link HTMLCollectionImpl} object with live collection of all
596      * forms in document. This reference is on demand only once.
597      */

598     private HTMLCollectionImpl _forms;
599
600
601     /**
602      * Holds {@link HTMLCollectionImpl} object with live collection of all
603      * images in document. This reference is on demand only once.
604      */

605     private HTMLCollectionImpl _images;
606
607
608     /**
609      * Holds {@link HTMLCollectionImpl} object with live collection of all
610      * links in document. This reference is on demand only once.
611      */

612     private HTMLCollectionImpl _links;
613
614
615     /**
616      * Holds {@link HTMLCollectionImpl} object with live collection of all
617      * applets in document. This reference is on demand only once.
618      */

619     private HTMLCollectionImpl _applets;
620
621
622     /**
623      * Holds string writer used by direct manipulation operation ({@link #open}.
624      * {@link #write}, etc) to write new contents into the document and parse
625      * that text into a document tree.
626      */

627     private StringWriter JavaDoc _writer;
628
629
630     /**
631      * Holds names and classes of HTML element types. When an element with a
632      * particular tag name is created, the matching {@link java.lang.Class}
633      * is used to create the element object. For example, &lt;A&gt; matches
634      * {@link HTMLAnchorElementImpl}. This static table is shared across all
635      * HTML documents, as opposed to the non-static table defined in {@link
636      * org.openxml.dom.DocumentImpl}.
637      *
638      * @see #createElement
639      */

640     private static Hashtable JavaDoc _elementTypesHTML;
641
642
643     /**
644      * Signature used to locate constructor of HTML element classes. This
645      * static array is shared across all HTML documents.
646      *
647      * @see #createElement
648      */

649     private final static Class JavaDoc[] _elemClassSigHTML = new Class JavaDoc[] {HTMLDocumentImpl.class, String JavaDoc.class};
650
651
652 }
653
Popular Tags