⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 collectionimpl.java

📁 Java的面向对象数据库系统的源代码
💻 JAVA
字号:
/**
 * org/ozone-db/xml/dom/CollectionImpl.java
 *
 * The contents of this file are subject to the OpenXML Public
 * License Version 1.0; you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 * http://www.openxml.org/license.html
 *
 * THIS SOFTWARE IS DISTRIBUTED ON AN "AS IS" BASIS WITHOUT WARRANTY
 * OF ANY KIND, EITHER EXPRESSED OR IMPLIED. THE INITIAL DEVELOPER
 * AND ALL CONTRIBUTORS SHALL NOT BE LIABLE FOR ANY DAMAGES AS A
 * RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
 * DERIVATIVES. SEE THE LICENSE FOR THE SPECIFIC LANGUAGE GOVERNING
 * RIGHTS AND LIMITATIONS UNDER THE LICENSE.
 *
 * The Initial Developer of this code under the License is Assaf Arkin.
 * Portions created by Assaf Arkin are Copyright (C) 1998, 1999.
 * All Rights Reserved.
 */

/**
 * Changes for Persistent DOM running with ozone are
 * Copyright 1999 by SMB GmbH. All rights reserved.
 */

package org.ozoneDB.xml.dom;

import org.w3c.dom.*;
import org.w3c.dom.html.*;
//import org.openxml.XMLCollection;


/**
 * Implements a live collection of elements. This collection is based on the
 * {@link org.w3c.dom.html.HTMLCollection} defined for HTML documents but works
 * with XML documents.
 * <P>
 * The collection is defined in terms of a root element and the elements to look
 * for under this root. Only elements of the specified type are contained in the
 * collection. Elements are returned by index or by identifier (the <TT>id</TT>
 * attribute). The collection is live, meaning that changes to the document tree
 * are immediately reflected in the collection. The collection is not optimized for
 * traversing large document trees.
 * <P>
 * The collection has to meet two requirements: it has to be live, and it has
 * to traverse depth first and always return results in that order. As such,
 * using an object container (such as {@link java.util.Vector}) is expensive on
 * insert/remove operations. Instead, the collection has been implemented using
 * three traversing functions. As a result, operations on large documents will
 * result in traversal of the entire document tree and consume a considerable
 * amount of time. * <P> * Note that synchronization on the traversed document cannot be achieved.
 * The document itself cannot be locked, and locking each traversed node is
 * likely to lead to a dead lock condition. Therefore, there is a chance of the
 * document being changed as results are fetched; in all likelihood, the results
 * might be out dated, but not erroneous.
 * <P>
 * Used to implement both {@link org.ozoneDB.xml.core.XMLCollection} and
 * {@link org.ozoneDB.xml.dom.html.HTMLAnchorElementImpl}. *
 *
 * @version $Revision: 1.2 $ $Date: 2003/11/20 23:18:42 $
 * @author <a href="mailto:arkin@trendline.co.il">Assaf Arkin</a>
 * @see org.w3c.dom.html.HTMLCollection
 */
public class CollectionImpl implements HTMLCollection {


    /**
     * Returns the length of the collection. This method might traverse the entire
     * document tree.
     *
     * @return Length of the collection
     */
    public final int getLength() {
        // Call recursive function on top-level element.
        return getLength( getTopLevel() );
    }


    /**
     * Retrieves the indexed node from the collection. Nodes are numbered in tree
     * order - depth-first traversal order. This method might traverse the entire
     * document tree.
     *
     * @param index The index of the node to return
     * @return The specified node or null if no such node found
     */
    public final Node item( int index ) {
        if (index < 0) {
            throw new IllegalArgumentException( "Argument 'index' is negative." );
        }
        // Call recursive function on top-level element.
        return item( getTopLevel(), new CollectionIndex( index ) );
    }


    /**
     * Retrieves the named node from the collection. The name is matched case
     * sensitive against the <TT>id</TT> attribute of each element in the
     * collection, returning the first match. The tree is traversed in depth-first
     * order. This method might traverse the entire document tree.
     *
     * @param name The name of the node to return
     * @return The specified node or null if no such node found
     */
    public final Node namedItem( String name ) {
        if (name == null) {
            throw new NullPointerException( "Argument 'name' is null." );
        }
        // Call recursive function on top-level element.
        return namedItem( getTopLevel(), name );
    }


    /**
     * Returns the top level element underneath which the collection exists.
     *
     * @return Top level element from which to scan
     */
    private Element getTopLevel() {
        return _topLevel;
    }


    /**
     * Recursive function returns the number of elements of a particular type that
     * exist under the top level element. This is a recursive function and the
     * top level element is passed along.
     *
     * @param topLevel Top level element from which to scan
     * @return Number of elements
     */
    private int getLength( Element topLevel ) {
        int length;
        Node node;

        synchronized (topLevel) {
            // Always count from zero and traverse all the childs of the current
            // element in the order they appear.
            length = 0;
            node = topLevel.getFirstChild();
            while (node != null) {
                // If a particular node is an element (could be HTML or XML), do two
                // things: if it's the one we're looking for, count another matched                // element; at any rate, traverse it's children as well.
                if (node instanceof Element) {
                    if (collectionMatch( (Element)node, null )) {
                        ++length;
                    }
                    if (recurse()) {
                        length += getLength( (Element)node );
                    }
                }
                node = node.getNextSibling();
            }
        }
        return length;
    }


    /**
     * Recursive function returns the numbered element of a particular type that
     * exist under the top level element. This is a recursive function and the
     * top level element is passed along.
     * <p>
     * Note that this function must call itself with an index and get back both
     * the element (if one was found) and the new index which is decremeneted
     * for any like element found. Since integers are only passed by value, this
     * function makes use of a separate class ({@link CollectionIndex}) to
     * hold that index.
     *
     * @param topLevel Top level element from which to scan
     * @param index The index of the item to retreive
     * @return Number of elements
     * @see CollectionIndex
     */
    private Node item( Element topLevel, CollectionIndex index ) {
        Node node;
        Node result;

        synchronized (topLevel) {
            // Traverse all the childs of the current element in the order they appear.
            // Count from the index backwards until you reach matching element with an
            // index of zero. Return that element.
            node = topLevel.getFirstChild();
            while (node != null) {
                // If a particular node is an element (could be HTML or XML), do two
                // things: if it's the one we're looking for, decrease the index and
                // if zero, return this node; at any rate, traverse it's children
                // as well.
                if (node instanceof Element) {
                    if (collectionMatch( (Element)node, null )) {
                        if (index.isZero()) {
                            return node;
                        }
                        index.decrement();
                    }
                    if (recurse()) {
                        result = item( (Element)node, index );
                        if (result != null) {
                            return result;
                        }
                    }
                }
                node = node.getNextSibling();
            }
        }
        return null;
    }


    /**
     * Recursive function returns an element of a particular type with the
     * specified name (<TT>ID</TT> attribute).
     *
     * @param topLevel Top level element from which to scan
     * @param name The named element to look for
     * @return The first named element found
     */
    private Node namedItem( Element topLevel, String name ) {
        Node node;
        Node result;
        synchronized (topLevel) {
            // Traverse all the childs of the current element in the order they appear.
            node = topLevel.getFirstChild();
            while (node != null) {
                // If a particular node is an element (could be HTML or XML),
                // do two things: if it's the one we're looking for, and the name
                // (ID attribute) attribute is the one we're looking for, return
                // this element; otherwise, traverse it's children.
                if (node instanceof Element) {
                    if (collectionMatch( (Element)node, name )) {
                        return node;
                    }
                    if (recurse()) {
                        result = namedItem( (Element)node, name );
                        if (result != null) {
                            return result;
                        }
                    }
                }

                node = node.getNextSibling();
            }
            return node;
        }
    }


    /**
     * Returns true if scanning methods should iterate through the collection.
     * When looking for elements in the document, recursing is needed to traverse
     * the full document tree. When looking inside a specific element (e.g. for a
     * cell inside a row), recursing can lead to erroneous results.
     *
     * @return True if methods should recurse to traverse entire tree
     */
    protected boolean recurse() {
        return true;
    }


    /**
     * Determines if current element matches based on what we're looking for.
     * The element is passed along with an optional identifier name. If the
     * element is the one we're looking for, return true. If the name is also
     * specified, the name must match the <TT>id</TT> attribute.
     *
     * @param elem The current element
     * @param name The identifier name or null
     * @return The element matches what we're looking for
     */
    protected boolean collectionMatch( Element elem, String name ) {
        boolean match;
        synchronized (elem) {
            match = elem.getTagName().equals( _lookForTag );
            if (match && name != null) {
                match = name.equals( elem.getAttribute( "id" ) );
            }
        }
        return match;
    }


    /**
     * Construct a new collection that retrieves element of the specific type
     * (<TT>lookFor</TT>) from the specific document portion (<TT>topLevel</TT>).
     *
     * @param topLevel The element underneath which the collection exists
     * @param lookFor Tag of element to look for
     */
    public CollectionImpl( Element topLevel, String lookFor ) {
        if (topLevel == null) {
            throw new NullPointerException( "Argument 'topLevel' is null." );
        }
        if (lookFor == null || lookFor.length() == 0) {
            throw new NullPointerException( "Argument 'lookFor' is null or an empty string." );
        }
        _topLevel = topLevel;
        _lookForTag = lookFor;
    }


    /**
     * Hidden constructor used by derived classes that might have different
     * _lookfor properties.
     *
     * @param topLevel The element underneath which the collection exists
     */
    public CollectionImpl( Element topLevel ) {
        if (topLevel == null) {
            throw new NullPointerException( "Argument 'topLevel' is null." );
        }
        _topLevel = topLevel;
    }

    /**
     * This is the top level element underneath which the collection exists.
     */
    private Element _topLevel;
    /**
     * This is the element type that this collection deals with. It identifies
     * the element's tag name, and only elements matching these tag names are
     * counted or returned by this collection.
     */
    private String _lookForTag;

}


/**
 * {@link CollectionImpl#item} must traverse down the tree and decrement the
 * index until it matches an element who's index is zero. Since integers are
 * passed by value, this class servers to pass the index into each recursion
 * by reference. It encompasses all the operations that need be performed on
 * the index, although direct access is possible.
 *
 * @see CollectionImpl#item
 */
class CollectionIndex {


    /**
     * Returns the current index.
     *
     * @return Current index
     */
    int getIndex() {
        return _index;
    }


    /**
     * Decrements the index by one.
     */
    void decrement() {
        --_index;
    }


    /**
     * Returns true if index is zero (or negative).
     *
     * @return True if index is zero
     */
    boolean isZero() {
        return _index <= 0;
    }


    /**
     * Constructs a new index with the specified initial value. The index will
     * then be decremeneted until it reaches zero.
     *
     * @param index The initial value
     */
    CollectionIndex( int index ) {
        _index = index;
    }

    /**
     * Holds the actual value that is passed by reference using this class.
     */
    private int _index;

}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -