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: <FRAMESET> 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, <A> 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 <HEAD> element in the document, creating one if does
240 * not exist before. The <HEAD> element is the first element in the
241 * <HTML> in the document. The <HTML> 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 <HEAD> element
247 * correctly placed.
248 *
249 * @return The <HEAD> 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