Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: org/enhydra/xml/lazydom/html/LazyHTMLDocument.java


1   /*
2    * Enhydra Java Application Server Project
3    * 
4    * The contents of this file are subject to the Enhydra Public License
5    * Version 1.1 (the "License"); you may not use this file except in
6    * compliance with the License. You may obtain a copy of the License on
7    * the Enhydra web site ( http://www.enhydra.org/ ).
8    * 
9    * Software distributed under the License is distributed on an "AS IS"
10   * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See 
11   * the License for the specific terms governing rights and limitations
12   * under the License.
13   * 
14   * The Initial Developer of the Enhydra Application Server is Lutris
15   * Technologies, Inc. The Enhydra Application Server and portions created
16   * by Lutris Technologies, Inc. are Copyright Lutris Technologies, Inc.
17   * All Rights Reserved.
18   * 
19   * Contributor(s):
20   * 
21   * $Id$
22   */
23  /*
24   * The Apache Software License, Version 1.1
25   *
26   *
27   * Copyright (c) 1999,2000 The Apache Software Foundation.  All rights 
28   * reserved.
29   *
30   * Redistribution and use in source and binary forms, with or without
31   * modification, are permitted provided that the following conditions
32   * are met:
33   *
34   * 1. Redistributions of source code must retain the above copyright
35   *    notice, this list of conditions and the following disclaimer. 
36   *
37   * 2. Redistributions in binary form must reproduce the above copyright
38   *    notice, this list of conditions and the following disclaimer in
39   *    the documentation and/or other materials provided with the
40   *    distribution.
41   *
42   * 3. The end-user documentation included with the redistribution,
43   *    if any, must include the following acknowledgment:  
44   *       "This product includes software developed by the
45   *        Apache Software Foundation (http://www.apache.org/)."
46   *    Alternately, this acknowledgment may appear in the software itself,
47   *    if and wherever such third-party acknowledgments normally appear.
48   *
49   * 4. The names "Xerces" and "Apache Software Foundation" must
50   *    not be used to endorse or promote products derived from this
51   *    software without prior written permission. For written 
52   *    permission, please contact apache@apache.org.
53   *
54   * 5. Products derived from this software may not be called "Apache",
55   *    nor may "Apache" appear in their name, without prior written
56   *    permission of the Apache Software Foundation.
57   *
58   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
59   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
60   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
61   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
62   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
63   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
64   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
65   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
66   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
67   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
68   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
69   * SUCH DAMAGE.
70   * ====================================================================
71   *
72   * This software consists of voluntary contributions made by many
73   * individuals on behalf of the Apache Software Foundation and was
74   * originally based on software copyright (c) 1999, International
75   * Business Machines, Inc., http://www.apache.org.  For more
76   * information on the Apache Software Foundation, please see
77   * <http://www.apache.org/>.
78   */
79  package org.enhydra.xml.lazydom.html;
80  
81  import java.io.*;
82  import java.util.*;
83  import java.lang.reflect.*;
84  import org.w3c.dom.*;
85  import org.w3c.dom.html.*;
86  import org.enhydra.xml.lazydom.TemplateDOM;
87  import org.enhydra.xml.lazydom.LazyDocument;
88  import org.enhydra.xml.lazydom.LazyNode;
89  import org.enhydra.xml.lazydom.LazyElement;
90  import org.enhydra.xml.lazydom.LazyElementNoNS;
91  import org.enhydra.xml.dom.DOMAccess;
92  
93  /*
94   * LazyDOM: This is a modified version of org.apache.html.dom.HTMLDocumentImpl
95   * modified to implement the LazyDOM.  While most of the HTMLElement classes
96   * are created automatically using a sed script, this was a bit complex for
97   * this class, so it was done by hand.  A diff with the Xerces class should
98   * make an upgrade of this class easy.
99   */
100 
101 
102 /**
103  * Implements an HTML document. Provides access to the top level element in the
104  * document, its body and title.
105  * <P>
106  * Several methods create new nodes of all basic types (comment, text, element,
107  * etc.). These methods create new nodes but do not place them in the document
108  * tree. The nodes may be placed in the document tree using {@link
109  * org.w3c.dom.Node#appendChild} or {@link org.w3c.dom.Node#insertBefore}, or
110  * they may be placed in some other document tree.
111  * <P>
112  * Note: &lt;FRAMESET&gt; documents are not supported at the moment, neither
113  * are direct document writing ({@link #open}, {@link #write}) and HTTP attribute
114  * methods ({@link #getURL}, {@link #getCookie}).
115  *
116  *
117  * @version $Revision$ $Date$
118  * @author <a href="mailto:arkin@exoffice.com">Assaf Arkin</a>
119  * @see org.w3c.dom.html.HTMLDocument
120  */
121 public class LazyHTMLDocument
122     extends LazyDocument
123     implements HTMLDocument
124 {
125 
126 
127     /**
128      * Holds {@link HTMLCollectionImpl} object with live collection of all
129      * anchors in document. This reference is on demand only once.
130      */
131     private HTMLCollectionImpl    _anchors;
132 
133 
134     /**
135      * Holds {@link HTMLCollectionImpl} object with live collection of all
136      * forms in document. This reference is on demand only once.
137      */
138     private HTMLCollectionImpl    _forms;
139 
140 
141     /**
142      * Holds {@link HTMLCollectionImpl} object with live collection of all
143      * images in document. This reference is on demand only once.
144      */
145     private HTMLCollectionImpl    _images;
146 
147 
148     /**
149      * Holds {@link HTMLCollectionImpl} object with live collection of all
150      * links in document. This reference is on demand only once.
151      */
152     private HTMLCollectionImpl    _links;
153 
154 
155     /**
156      * Holds {@link HTMLCollectionImpl} object with live collection of all
157      * applets in document. This reference is on demand only once.
158      */
159     private HTMLCollectionImpl    _applets;
160 
161 
162     /**
163      * Holds string writer used by direct manipulation operation ({@link #open}.
164      * {@link #write}, etc) to write new contents into the document and parse
165      * that text into a document tree.
166      */
167     private StringWriter        _writer;
168 
169 
170     /**
171      * Holds names and classes of HTML element types. When an element with a
172      * particular tag name is created, the matching {@link java.lang.Class}
173      * is used to create the element object. For example, &lt;A&gt; matches
174      * {@link HTMLAnchorElementImpl}. This static table is shared across all
175      * HTML documents.
176      *
177      * @see #createElement
178      */
179     private static Hashtable        _elementTypesHTML;
180 
181 
182     /**
183      * Signature used to locate constructor of HTML element classes. This
184      * static array is shared across all HTML documents.
185      *
186      * @see #createElement
187      */
188     private static final Class[]    _elemClassSigHTML =
189         new Class[] { LazyHTMLDocument.class, LazyElement.class, String.class };
190 
191 
192     /**
193      */
194     public LazyHTMLDocument()
195     {
196         super();
197         populateElementTypes();
198     }
199 
200      /**
201      * @see Document#DOMImplementation
202      */
203     public DOMImplementation getImplementation() {
204         return LazyHTMLDOMImplementation.getDOMImplementation();
205     }
206     
207 
208    /**
209      * Find the direct child element of a node given its name.
210      */
211     private Node getDirectChildElement(String name,
212                                        Node root) {
213         for (Node child = root.getFirstChild(); child != null;
214              child = child.getNextSibling()) {
215             if (child.getNodeName().equals(name)) {
216                 return child;
217             }
218         }
219         return null;
220     }
221 
222 
223     public synchronized Element getDocumentElement() {
224         // Enhydra modified: Original Xerces code tried to reorder nodes to
225         // make things right, which moved around comments to weird locations.
226         // Throwing an error would be more appropriate, but we were afraid of
227         // breaking existing code, so just get the node.
228 
229         Element html = (Element)getDirectChildElement("HTML", this);
230         if (html == null) {
231             // Create, HTML element must exist as a child of the document.
232             html = new HTMLHtmlElementImpl(this, null, "HTML");
233             appendChild(html);
234         }
235         return html;
236     }
237     
238     /**
239      * Obtains the &lt;HEAD&gt; element in the document, creating one if does
240      * not exist before. The &lt;HEAD&gt; element is the first element in the
241      * &lt;HTML&gt; in the document. The &lt;HTML&gt; element is obtained by
242      * calling {@link #getDocumentElement}. If the element does not exist, one
243      * is created.
244      * <P>
245      * Called by {@link #getTitle}, {@link #setTitle}, {@link #getBody} and
246      * {@link #setBody} to assure the document has the &lt;HEAD&gt; element
247      * correctly placed.
248      *
249      * @return The &lt;HEAD&gt; element
250      */
251     public synchronized HTMLElement getHead() {
252         // Enhydra modified: Original Xerces code tried to reorder nodes to
253         // make things right, which moved around comments to weird locations.
254         // Throwing an error would be more appropriate, but we were afraid of
255         // breaking existing code, so just get the node.
256 
257         // Search for HEAD under HTML element.
258         Element html = getDocumentElement();
259         HTMLElement head
260             = (HTMLElement)getDirectChildElement("HEAD", html);
261         if (head == null) {
262             // Head does not exist, create a new one.
263             head = new HTMLHeadElementImpl(this, null, "HEAD");
264             html.insertBefore(head, html.getFirstChild());
265         }
266         return head;
267     }
268 
269     public synchronized String getTitle() {
270         // Enhydra modified: Original Xerces code is some what strange, it
271         // called getElementsByTagName() twice, but only used the second
272         // result.  We assume it' a direct child of HEAD (although more 
273         // error checking might be better).
274 
275         HTMLTitleElement title
276             = (HTMLTitleElement)getDirectChildElement("TITLE", getHead());
277         if (title == null) {
278             return ""; // No TITLE found, return an empty string.
279         } else {
280             return title.getText();
281         }
282     }
283 
284 
285     public synchronized void setTitle(String newTitle) {
286         // Enhydra modified: Original Xerces code used getElementsByTagName()
287         // to find the title.  We assume it' a direct child of HEAD (although
288         // more error checking might be better).
289 
290         HTMLElement head = getHead();
291         HTMLTitleElement title
292             = (HTMLTitleElement)getDirectChildElement("TITLE", head);
293         if (title == null) {
294             title = new HTMLTitleElementImpl(this, null, "TITLE");
295         }
296         title.setText(newTitle);
297     }
298 
299     /**
300      * Find a BODY or FRAMESET element.
301      */
302     private HTMLElement findBody(Element html) {
303         HTMLElement body = (HTMLElement)getDirectChildElement("BODY", html);
304         if (body == null) {
305             body = (HTMLElement)getDirectChildElement("FRAMESET", html);
306         }
307         return body;
308     }
309 
310     public synchronized HTMLElement getBody() {
311         // Enhydra modified: Original Xerces code tried to reorder nodes to
312         // make things right, which moved around comments to weird locations.
313         // Throwing an error would be more appropriate, but we were afraid of
314         // breaking existing code, so just get the node.
315 
316         // Find BODY or FRAMESET
317         Element html = getDocumentElement();
318         HTMLElement body = findBody(html);
319         if (body == null) {
320             // Create new body, and place it a the end of the HTML element.
321             body = new HTMLBodyElementImpl(this, null, "BODY");
322             html.appendChild(body);
323         }
324         return body;
325     }
326 
327 
328     public synchronized void setBody(HTMLElement newBody) {
329         // Enhydra modified: Original Xerces code tried to reorder nodes to
330         // make things right, which moved around comments to weird locations.
331         // Throwing an error would be more appropriate, but we were afraid of
332         // breaking existing code, so just get the node.
333 
334         // Find BODY or FRAMESET
335         Element html = getDocumentElement();
336         HTMLElement body = findBody(html);
337         if (body == null) {
338             html.appendChild(newBody);
339         } else {
340             html.replaceChild(newBody, body);
341         }
342     }
343 
344 
345     public synchronized Element getElementById( String elementId )
346     {
347         return getElementById( elementId, this );
348     }
349 
350 
351     public NodeList getElementsByName( String elementName )
352     {
353         return new NameNodeListImpl( this, elementName );
354     }
355 
356 
357     public final NodeList getElementsByTagName( String tagName )
358     {
359         return super.getElementsByTagName( tagName.toUpperCase() );
360     }
361 
362 
363     public final NodeList getElementsByTagNameNS( String namespaceURI,
364                                                   String localName )
365     {
366         if ( namespaceURI != null && namespaceURI.length() > 0 )
367             return super.getElementsByTagNameNS( namespaceURI, localName.toUpperCase() );
368         else
369             return super.getElementsByTagName( localName.toUpperCase() );
370     } 
371 
372 
373     public Element createElementNS( String namespaceURI, String qualifiedName )
374     {
375         if ( namespaceURI == null || namespaceURI.length() == 0 )
376             return createElement( qualifiedName );
377         else
378             return super.createElementNS( namespaceURI, qualifiedName );
379     }
380 
381 
382     public Element createElement( LazyElement template, String tagName )
383         throws DOMException
384     {
385         Class        elemClass;
386         Constructor    cnst;
387 
388         // First, make sure tag name is all upper case, next get the associated
389         // element class. If no class is found, generate a generic HTML element.
390         // Do so also if an unexpected exception occurs.
391         tagName = tagName.toUpperCase();
392         elemClass = (Class) _elementTypesHTML.get( tagName );
393         if ( elemClass != null )
394         {
395             // Get the constructor for the element. The signature specifies an
396             // owner document and a tag name. Use the constructor to instantiate
397             // a new object and return it.
398             try
399             {
400                 cnst = elemClass.getConstructor( _elemClassSigHTML );
401                 return (Element) cnst.newInstance( new Object[] { this, template, tagName } );
402             }
403             catch ( Exception except )
404             {
405                 Throwable thrw;
406 
407                 if ( except instanceof java.lang.reflect.InvocationTargetException )
408                     thrw = ( (java.lang.reflect.InvocationTargetException) except ).getTargetException();
409                 else
410                     thrw = except;
411 
412                 throw new IllegalStateException( "HTM15 Tag '" + tagName + "' associated with an Element class that failed to construct.\n" + tagName);
413             }
414         }
415         return new LazyHTMLElement( this, template, tagName );
416     }
417 
418 
419     /**
420      * Creates an Attribute having this Document as its OwnerDoc.
421      * Overrides {@link DocumentImpl#createAttribute} and returns
422      * and attribute whose name is lower case.
423      *
424      * @param name The name of the attribute
425      * @return An attribute whose name is all lower case
426      * @throws DOMException(INVALID_NAME_ERR) if the attribute name
427      *   is not acceptable
428      */
429     public Attr createAttribute( String name )
430         throws DOMException
431     {
432         return super.createAttribute( name.toLowerCase() );
433     }
434 
435 
436     public String getReferrer()
437     {
438         // Information not available on server side.
439         return null;
440     }
441 
442 
443     public String getDomain()
444     {
445         // Information not available on server side.
446         return null;
447     }
448 
449 
450     public String getURL()
451     {
452         // Information not available on server side.
453         return null;
454     }
455 
456 
457     public String getCookie()
458     {
459         // Information not available on server side.
460         return null;
461     }
462 
463 
464     public void setCookie( String cookie )
465     {
466         // Information not available on server side.
467     }
468 
469 
470     public HTMLCollection getImages()
471     {
472         // For more information see HTMLCollection#collectionMatch
473         if ( _images == null )
474             _images = new HTMLCollectionImpl( getBody(), HTMLCollectionImpl.IMAGE );
475         return _images;
476     }
477 
478 
479     public HTMLCollection getApplets()
480     {
481         // For more information see HTMLCollection#collectionMatch
482         if ( _applets == null )
483             _applets = new HTMLCollectionImpl( getBody(), HTMLCollectionImpl.APPLET );
484         return _applets;
485     }
486 
487 
488     public HTMLCollection getLinks()
489     {
490         // For more information see HTMLCollection#collectionMatch
491         if ( _links == null )
492             _links = new HTMLCollectionImpl( getBody(), HTMLCollectionImpl.LINK );
493         return _links;
494     }
495 
496 
497     public HTMLCollection getForms()
498     {
499         // For more information see HTMLCollection#collectionMatch
500         if ( _forms == null )
501             _forms = new HTMLCollectionImpl( getBody(), HTMLCollectionImpl.FORM );
502         return _forms;
503     }
504 
505 
506     public HTMLCollection getAnchors()
507     {
508         // For more information see HTMLCollection#collectionMatch
509         if ( _anchors == null )
510             _anchors = new HTMLCollectionImpl( getBody(), HTMLCollectionImpl.ANCHOR );
511         return _anchors;
512     }
513 
514 
515     public void open()
516     {
517         // When called an in-memory is prepared. The document tree is still
518         // accessible the old way, until this writer is closed.
519         if ( _writer == null )
520             _writer = new StringWriter();
521     }
522 
523 
524     public void close()
525     {
526         // ! NOT IMPLEMENTED, REQUIRES PARSER !
527         if ( _writer != null )
528         {
529             _writer = null;
530         }
531     }
532 
533 
534     public void write( String text )
535     {
536         // Write a string into the in-memory writer.
537         if ( _writer != null )
538             _writer.write( text );
539     }
540 
541 
542     public void writeln( String text )
543     {
544         // Write a line into the in-memory writer.
545         if ( _writer != null )
546             _writer.write( text + "\n" );
547     }
548 
549 
550     public Node cloneNode( boolean deep )
551     {
552         LazyHTMLDocument    clone;
553         LazyNode            node;
554         
555         clone = new LazyHTMLDocument();
556         if ( deep ) {
557             node = (LazyNode) getFirstChild();
558             while ( node != null ) {
559                 clone.appendChild( clone.importNode( node, true ) );
560                 node = (LazyNode) node.getNextSibling();
561             }
562         }
563         return clone;
564     }
565 
566 
567     /**
568      * Recursive method retreives an element by its <code>id</code> attribute.
569      * This is LazyDOM aware and will not expand elements during search.
570      *
571      * @param elementId The <code>id</code> value to look for
572      * @return The node in which to look for
573      */
574     private Element getElementById(String elementId,
575                                    Node node){
576         Node child;
577         Element element;
578 
579         child = DOMAccess.accessFirstChild(this, node);
580         while (child != null) {
581             if (child instanceof Element) {
582                 element = (Element)child;
583                 Attr attr = DOMAccess.accessAttribute(this, (Element)child, null, "id");
584                 if ((attr != null)
585                     && elementId.equals(DOMAccess.accessAttributeValue(this, attr))) {
586                     return DOMAccess.getExpandedElement(this, element);
587                 }
588                 // Recurse
589                 element = getElementById(elementId, child);
590                 if (element != null) {
591                     return DOMAccess.getExpandedElement(this, element);
592                 }
593             }
594             child =  DOMAccess.accessNextSibling(this, child);
595         }
596         return null;
597     }
598 
599 
600     /**
601      * Called by the constructor to populate the element types list (see {@link
602      * #_elementTypesHTML}). Will be called multiple times but populate the list
603      * only the first time. Replacement for static constructor.
604      */
605     private static void populateElementTypes()
606     {
607         // This class looks like it is due to some strange
608         // (read: inconsistent) JVM bugs.
609         // Initially all this code was placed in the static constructor,
610         // but that caused some early JVMs (1.1) to go mad, and if a
611         // class could not be found (as happened during development),
612         // the JVM would die.
613         // Bertrand Delacretaz <bdelacretaz@worldcom.ch> pointed out
614         // several configurations where HTMLAnchorElementImpl.class
615         // failed, forcing me to revert back to Class.forName().
616         
617         if ( _elementTypesHTML != null )
618             return;
619         _elementTypesHTML = new Hashtable( 63 );
620         populateElementType( "A", "HTMLAnchorElementImpl" );
621         populateElementType( "APPLET", "HTMLAppletElementImpl" );
622         populateElementType( "AREA", "HTMLAreaElementImpl" );
623         populateElementType( "BASE",  "HTMLBaseElementImpl" );
624         populateElementType( "BASEFONT", "HTMLBaseFontElementImpl" );
625         populateElementType( "BLOCKQUOTE", "HTMLQuoteElementImpl" );
626         populateElementType( "BODY", "HTMLBodyElementImpl" );
627         populateElementType( "BR", "HTMLBRElementImpl" );
628         populateElementType( "BUTTON", "HTMLButtonElementImpl" );
629         populateElementType( "DEL", "HTMLModElementImpl" );
630         populateElementType( "DIR", "HTMLDirectoryElementImpl" );
631         populateElementType( "DIV",  "HTMLDivElementImpl" );
632         populateElementType( "DL", "HTMLDListElementImpl" );
633         populateElementType( "FIELDSET", "HTMLFieldSetElementImpl" );
634         populateElementType( "FONT", "HTMLFontElementImpl" );
635         populateElementType( "FORM", "HTMLFormElementImpl" );
636         populateElementType( "FRAME","HTMLFrameElementImpl" );
637         populateElementType( "FRAMESET", "HTMLFrameSetElementImpl" );
638         populateElementType( "HEAD", "HTMLHeadElementImpl" );
639         populateElementType( "H1", "HTMLHeadingElementImpl" );
640         populateElementType( "H2", "HTMLHeadingElementImpl" );
641         populateElementType( "H3", "HTMLHeadingElementImpl" );
642         populateElementType( "H4", "HTMLHeadingElementImpl" );
643         populateElementType( "H5", "HTMLHeadingElementImpl" );
644         populateElementType( "H6", "HTMLHeadingElementImpl" );
645         populateElementType( "HR", "HTMLHRElementImpl" );
646         populateElementType( "HTML", "HTMLHtmlElementImpl" );
647         populateElementType( "IFRAME", "HTMLIFrameElementImpl" );
648         populateElementType( "IMG", "HTMLImageElementImpl" );
649         populateElementType( "INPUT", "HTMLInputElementImpl" );
650         populateElementType( "INS", "HTMLModElementImpl" );
651         populateElementType( "ISINDEX", "HTMLIsIndexElementImpl" );
652         populateElementType( "LABEL", "HTMLLabelElementImpl" );
653         populateElementType( "LEGEND", "HTMLLegendElementImpl" );
654         populateElementType( "LI", "HTMLLIElementImpl" );
655         populateElementType( "LINK", "HTMLLinkElementImpl" );
656         populateElementType( "MAP", "HTMLMapElementImpl" );
657         populateElementType( "MENU", "HTMLMenuElementImpl" );
658         populateElementType( "META", "HTMLMetaElementImpl" );
659         populateElementType( "OBJECT", "HTMLObjectElementImpl" );
660         populateElementType( "OL", "HTMLOListElementImpl" );
661         populateElementType( "OPTGROUP", "HTMLOptGroupElementImpl" );
662         populateElementType( "OPTION", "HTMLOptionElementImpl" );
663         populateElementType( "P", "HTMLParagraphElementImpl" );
664         populateElementType( "PARAM", "HTMLParamElementImpl" );
665         populateElementType( "PRE", "HTMLPreElementImpl" );
666         populateElementType( "Q", "HTMLQuoteElementImpl" );
667         populateElementType( "SCRIPT", "HTMLScriptElementImpl" );
668         populateElementType( "SELECT", "HTMLSelectElementImpl" );
669         populateElementType( "STYLE", "HTMLStyleElementImpl" );
670         populateElementType( "TABLE", "HTMLTableElementImpl" );
671         populateElementType( "CAPTION", "HTMLTableCaptionElementImpl" );
672         populateElementType( "TD", "HTMLTableCellElementImpl" );
673         populateElementType( "TH", "HTMLTableCellElementImpl" );
674         populateElementType( "COL", "HTMLTableColElementImpl" );
675         populateElementType( "COLGROUP", "HTMLTableColElementImpl" );
676         populateElementType( "TR", "HTMLTableRowElementImpl" );
677         populateElementType( "TBODY", "HTMLTableSectionElementImpl" );
678         populateElementType( "THEAD", "HTMLTableSectionElementImpl" );
679         populateElementType( "TFOOT", "HTMLTableSectionElementImpl" );
680         populateElementType( "TEXTAREA", "HTMLTextAreaElementImpl" );
681         populateElementType( "TITLE", "HTMLTitleElementImpl" );
682         populateElementType( "UL", "HTMLUListElementImpl" );
683     }
684     
685     
686     private static void populateElementType( String tagName, String className )
687     {
688         try {
689             _elementTypesHTML.put( tagName, Class.forName( "org.enhydra.xml.lazydom.html." + className ) );
690         } catch ( ClassNotFoundException except ) {
691             new RuntimeException( "HTM019 OpenXML Error: Could not find class " + className + " implementing HTML element " + tagName
692                                   + "\n" + className + "\t" + tagName);
693         }
694     }
695 
696     /**
697      * LazyDOM: Constructor with TemplateDOM.
698      */
699     public LazyHTMLDocument(TemplateDOM templateDOM) {
700         super(null, templateDOM);
701         populateElementTypes();
702     }
703 
704     /**
705      * LazyDOM: standard createElement method, passes null template element.
706      */
707     public Element createElement(String tagName) throws DOMException {
708         return createElement(null, tagName);
709     }
710 
711     /*
712      * Lazy DOM override to pick up HTML elements.
713      */
714     public LazyElement createElement(int nodeId) throws DOMException {
715         LazyElement template = (LazyElement)getTemplateNode(nodeId);
716         return (LazyElement)createElement(template, template.getNodeName());
717     }
718 }
719