001: /**
002: * org/ozone-db/xml/dom/html/HTMLCollectionImpl.java
003: *
004: * The contents of this file are subject to the OpenXML Public
005: * License Version 1.0; you may not use this file except in compliance
006: * with the License. You may obtain a copy of the License at
007: * http://www.openxml.org/license.html
008: *
009: * THIS SOFTWARE IS DISTRIBUTED ON AN "AS IS" BASIS WITHOUT WARRANTY
010: * OF ANY KIND, EITHER EXPRESSED OR IMPLIED. THE INITIAL DEVELOPER
011: * AND ALL CONTRIBUTORS SHALL NOT BE LIABLE FOR ANY DAMAGES AS A
012: * RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
013: * DERIVATIVES. SEE THE LICENSE FOR THE SPECIFIC LANGUAGE GOVERNING
014: * RIGHTS AND LIMITATIONS UNDER THE LICENSE.
015: *
016: * The Initial Developer of this code under the License is Assaf Arkin.
017: * Portions created by Assaf Arkin are Copyright (C) 1998, 1999.
018: * All Rights Reserved.
019: */package org.ozoneDB.xml.dom.html;
020:
021: import org.w3c.dom.*;
022: import org.w3c.dom.html.*;
023: import org.ozoneDB.xml.dom.*;
024:
025: /**
026: * Implements {@link org.w3c.dom.html.HTMLCollection} to traverse any named
027: * elements on a {@link org.w3c.dom.html.HTMLDocument}. The elements type to
028: * look for is identified in the constructor by code. This collection is not
029: * optimized for traversing large trees.
030: * <p>
031: * The collection has to meet two requirements: it has to be live, and it has
032: * to traverse depth first and always return results in that order. As such,
033: * using an object container (such as {@link java.util.Vector}) is expensive on
034: * insert/remove operations. Instead, the collection has been implemented using
035: * three traversing functions. As a result, operations on large documents will
036: * result in traversal of the entire document tree and consume a considerable
037: * amount of time.
038: * <p>
039: * Note that synchronization on the traversed document cannot be achieved.
040: * The document itself cannot be locked, and locking each traversed node is
041: * likely to lead to a dead lock condition. Therefore, there is a chance of the
042: * document being changed as results are fetched; in all likelihood, the results
043: * might be out dated, but not erroneous.
044: *
045: *
046: * @version $Revision: 1.1 $ $Date: 2001/12/18 11:03:24 $
047: * @author <a href="mailto:arkin@trendline.co.il">Assaf Arkin</a>
048: * @see org.w3c.dom.html.HTMLCollection
049: * @see org.openxml.dom.CollectionImpl
050: */
051: final class HTMLCollectionImpl extends CollectionImpl implements
052: HTMLCollection {
053:
054: /**
055: * Returns true if scanning methods should iterate through the collection.
056: * When looking for elements in the document, recursing is needed to traverse
057: * the full document tree. When looking inside a specific element (e.g. for a
058: * cell inside a row), recursing can lead to erroneous results.
059: *
060: * @return True if methods should recurse to traverse entire tree
061: */
062: protected boolean recurse() {
063: return _lookingFor > 0;
064: }
065:
066: /**
067: * Determines if current element matches based on what we're looking for.
068: * The element is passed along with an optional identifier name. If the
069: * element is the one we're looking for, return true. If the name is also
070: * specified, the name must match the <code>id</code> attribute
071: * (match <code>name</code> first for anchors).
072: *
073: * @param elem The current element
074: * @param name The identifier name or null
075: * @return The element matches what we're looking for
076: */
077: protected boolean collectionMatch(Element elem, String name) {
078: boolean match;
079:
080: synchronized (elem) {
081: // Begin with no matching. Depending on what we're looking for,
082: // attempt to match based on the element type. This is the quickest
083: // way to match involving only a cast. Do the expensive string
084: // comparison later on.
085: match = false;
086: switch (_lookingFor) {
087: case ANCHOR:
088: // Anchor is an <A> element with a 'name' attribute. Otherwise, it's
089: // just a link.
090: match = elem instanceof HTMLAnchorElement
091: && elem.getAttribute("name") != null;
092: break;
093: case FORM:
094: // Any <FORM> element.
095: match = elem instanceof HTMLFormElement;
096: break;
097: case IMAGE:
098: // Any <IMG> element. <OBJECT> elements with images are not returned.
099: match = elem instanceof HTMLImageElement;
100: break;
101: case APPLET:
102: // Any <APPLET> element, and any <OBJECT> element which represents an
103: // Applet. This is determined by 'codetype' attribute being
104: // 'application/java' or 'classid' attribute starting with 'java:'.
105: match = elem instanceof HTMLAppletElement
106: || elem instanceof HTMLObjectElement
107: && ("application/java".equals(elem
108: .getAttribute("codetype")) || elem
109: .getAttribute("classid") != null
110: && elem.getAttribute("classid")
111: .startsWith("java:"));
112: break;
113: case ELEMENT:
114: // All form elements implement HTMLFormControl for easy identification.
115: match = elem instanceof HTMLFormControl;
116: break;
117: case LINK:
118: // Any <A> element, and any <AREA> elements with an 'href' attribute.
119: match = (elem instanceof HTMLAnchorElement || elem instanceof HTMLAreaElement)
120: && elem.getAttribute("href") != null;
121: break;
122: case AREA:
123: // Any <AREA> element.
124: match = elem instanceof HTMLAreaElement;
125: break;
126: case OPTION:
127: // Any <OPTION> element.
128: match = elem instanceof HTMLOptionElement;
129: break;
130: case ROW:
131: // Any <TR> element.
132: match = elem instanceof HTMLTableRowElement;
133: break;
134: case TBODY:
135: // Any <TBODY> element (one of three table section types).
136: match = elem instanceof HTMLTableSectionElement
137: && elem.getTagName().equals("tbody");
138: break;
139: case CELL:
140: // Any <TD> element.
141: match = elem instanceof HTMLTableCellElement;
142: break;
143: }
144:
145: // If element type was matched and a name was specified, must also match
146: // the name against either the 'id' or the 'name' attribute. The 'name'
147: // attribute is relevant only for <A> elements for backward compatibility.
148: if (match && name != null) {
149: // If an anchor and 'name' attribute matches, return true. Otherwise,
150: // try 'id' attribute.
151: if (elem instanceof HTMLAnchorElement
152: && name.equals(elem.getAttribute("name"))) {
153: return true;
154: }
155: match = name.equals(elem.getAttribute("id"));
156: }
157: }
158: return match;
159: }
160:
161: /**
162: * Construct a new collection that retrieves element of the specific type
163: * (<code>lookingFor</code>) from the specific document portion
164: * (<code>topLevel</code>).
165: *
166: * @param topLevel The element underneath which the collection exists
167: * @param lookingFor Code indicating what elements to look for
168: */
169: HTMLCollectionImpl(HTMLElement topLevel, short lookingFor) {
170: super (topLevel);
171: _lookingFor = lookingFor;
172: }
173:
174: /**
175: * Request collection of all anchors in document: <A> elements that
176: * have a <code>name</code> attribute.
177: */
178: final static short ANCHOR = 1;
179:
180: /**
181: * Request collection of all forms in document: <FORM> elements.
182: */
183: final static short FORM = 2;
184:
185: /**
186: * Request collection of all images in document: <IMAGE> elements.
187: */
188: final static short IMAGE = 3;
189:
190: /**
191: * Request collection of all Applets in document: <APPLET> and
192: * <OBJECT> elements (<OBJECT> must contain an Applet).
193: */
194: final static short APPLET = 4;
195:
196: /**
197: * Request collection of all links in document: <A> and <AREA>
198: * elements (must have a <code>href</code> attribute).
199: */
200: final static short LINK = 5;
201:
202: /**
203: * Request collection of all options in selection: <OPTION> elments in
204: * <SELECT> or <OPTGROUP>.
205: */
206: final static short OPTION = 6;
207:
208: /**
209: * Request collection of all rows in table: <TR> elements in table or
210: * table section.
211: */
212: final static short ROW = 7;
213:
214: /**
215: * Request collection of all form elements: <INPUT>, <BUTTON>,
216: * <SELECT>, <TEXT> and <TEXTAREA> elements inside form
217: * <FORM>.
218: */
219: final static short ELEMENT = 8;
220:
221: /**
222: * Request collection of all areas in map: <AREA> element in <MAP>
223: * (non recursive).
224: */
225: final static short AREA = -1;
226:
227: /**
228: * Request collection of all table bodies in table: <TBODY> element in
229: * table <TABLE> (non recursive).
230: */
231: final static short TBODY = -2;
232:
233: /**
234: * Request collection of all cells in row: <TD> elements in <TR>
235: * (non recursive).
236: */
237: final static short CELL = -3;
238:
239: /**
240: * Indicates what this collection is looking for. Holds one of the enumerated
241: * values and used by {@link #collectionMatch}. Set by the constructor and
242: * determine the collection's use for its life time.
243: */
244: private short _lookingFor;
245:
246: }
|