All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.enhydra.xml.xhtml.dom.xerces.XHTMLDocumentBase Maven / Gradle / Ivy

The newest version!
/*
 * The Apache Software License, Version 1.1
 * 
 * 
 * Copyright (c) 1999,2000 The Apache Software Foundation.  All rights
 * reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 
 * 1. Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 * 
 * 2. Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in
 * the documentation and/or other materials provided with the
 * distribution.
 * 
 * 3. The end-user documentation included with the redistribution,
 * if any, must include the following acknowledgment:
 * "This product includes software developed by the
 * Apache Software Foundation (http://www.apache.org/)."
 * Alternately, this acknowledgment may appear in the software itself,
 * if and wherever such third-party acknowledgments normally appear.
 * 
 * 4. The names "Xerces" and "Apache Software Foundation" must
 * not be used to endorse or promote products derived from this
 * software without prior written permission. For written
 * permission, please contact [email protected].
 * 
 * 5. Products derived from this software may not be called "Apache",
 * nor may "Apache" appear in their name, without prior written
 * permission of the Apache Software Foundation.
 * 
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 * 
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation and was
 * originally based on software copyright (c) 1999, International
 * Business Machines, Inc., http://www.apache.org.  For more
 * information on the Apache Software Foundation, please see
 * .
 */
package org.enhydra.xml.xhtml.dom.xerces;

/*
 * Derived from Xerces HTMLDocument implementation.
 * Author: Assaf Arkin 
 */
import java.io.StringWriter;
import java.lang.reflect.Constructor;
import java.util.HashMap;

import org.enhydra.apache.html.dom.HTMLAnchorElementImpl;
import org.enhydra.apache.xerces.dom.DocumentImpl;
import org.enhydra.apache.xerces.dom.NodeImpl;
import org.enhydra.xml.xmlc.XMLCError;
import org.w3c.dom.DOMException;
import org.w3c.dom.DOMImplementation;
import org.w3c.dom.DocumentType;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.html.HTMLCollection;
import org.w3c.dom.html.HTMLDocument;
import org.w3c.dom.html.HTMLElement;
import org.w3c.dom.html.HTMLTitleElement;

/**
 * Base class used to implements documents defined in terms of XHTML.  This
 * includes the full XHTML and XHTML modular documents. This defined all of
 * the HTMLDocument methods plus a framework for creating elements, but no
 * element definitions themselves.
 * 
 * @see org.w3c.dom.html.HTMLDocument
 */
public class XHTMLDocumentBase extends DocumentImpl implements HTMLDocument {
    /**
     * Holds {@link XHTMLCollectionImpl} object with live collection of all
     * anchors in document. This reference is on demand only once.
     */
    private XHTMLCollectionImpl fAnchors;

    /**
     * Holds {@link XHTMLCollectionImpl} object with live collection of all
     * forms in document. This reference is on demand only once.
     */
    private XHTMLCollectionImpl fForms;

    /**
     * Holds {@link XHTMLCollectionImpl} object with live collection of all
     * images in document. This reference is on demand only once.
     */
    private XHTMLCollectionImpl fImages;

    /**
     * Holds {@link XHTMLCollectionImpl} object with live collection of all
     * links in document. This reference is on demand only once.
     */
    private XHTMLCollectionImpl fLinks;


    /**
     * Holds {@link XHTMLCollectionImpl} object with live collection of all
     * applets in document. This reference is on demand only once.
     */
    private XHTMLCollectionImpl fApplets;

    /**
     * Holds string writer used by direct manipulation operation ({@link #open}.
     * {@link #write}, etc) to write new contents into the document and parse
     * that text into a document tree.
     */
    private StringWriter fWriter;

    /**
     * Holds names and classes of HTML element types. When an element with a
     * particular tag name is created, the matching {@link java.lang.Class}
     * is used to create the element object. For example, <A> matches
     * {@link HTMLAnchorElementImpl}. This static table is shared across all
     * HTML documents.
     * 
     * @see #createElement
     */
    private static HashMap fElementTypes;

    /**
     * Signature used to locate constructor of HTML element classes. This
     * static array is shared across all HTML documents.
     * 
     * @see #createElement
     */
    private static final Class[] fElemConstructorSig = new Class[] {
	XHTMLDocumentBase.class, String.class, String.class
    };

    /**
     * Constructor without document type.
     *
     * @param elementTypes Map of element names to element classes.
     */
    public XHTMLDocumentBase(HashMap elementTypes) {
	super();
        fElementTypes = elementTypes;
    }

    /**
     * Constructor with document type.
     */
    public XHTMLDocumentBase(DocumentType doctype,
                             HashMap elementTypes) {
	super(doctype);
        fElementTypes = elementTypes;
    }

    /**
     * Find the direct child element of a node given its name.
     */
    private Node getDirectChildElement(String name, Node root) {
	for (Node child = root.getFirstChild(); child != null; 
		child = child.getNextSibling()) {
	    if ((child instanceof Element)
                && child.getNodeName().equals(name)) {
		return child;
	    } 
	} 

	return null;
    } 

    /**
     * @see org.enhydra.apache.html.dom.HTMLDocumentImpl#getDocumentElement
     */
    public synchronized Element getDocumentElement() {
	Element html = (Element)getDirectChildElement("html", this);
	if (html == null) {
            throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR,
                                   " document element not found");
	} 

	return html;
    } 

    /**
     * Obtains the <HEAD> element in the document, creating one if does
     * not exist before. The <HEAD> element is the first element in the
     * <HTML> in the document. The <HTML> element is obtained by
     * calling {@link #getDocumentElement}. If the element does not exist, one
     * is created.
     * 
     * @return The <HEAD> element
     */
    public synchronized HTMLElement getHead() {

	// Enhydra modified: Original Xerces code tried to reorder nodes to
	// make things right, which moved around comments to weird locations.
	// Throwing an error would be more appropriate, but we were afraid of
	// breaking existing code, so just get the node.
	// Search for HEAD under HTML element.
	Element html = getDocumentElement();
	HTMLElement head = (HTMLElement)getDirectChildElement("head", html);

	if (head == null) {
	    // Head does not exist, create a new one.
	    head = new XHTMLHeadElementImpl(this, html.getNamespaceURI(),
                                            "head");
	    html.insertBefore(head, html.getFirstChild());
	} 

	return head;
    } 

    /**
     * @see org.enhydra.apache.html.dom.HTMLDocumentImpl#getTitle
     */
    public synchronized String getTitle() {
	// Enhydra modified: Original Xerces code is some what strange, it
	// called getElementsByTagName() twice, but only used the second
	// result.  We assume it' a direct child of HEAD (although more
	// error checking might be better).
	HTMLTitleElement title = 
	    (HTMLTitleElement)getDirectChildElement("title", getHead());

	if (title == null) {
	    return "";    // No TITLE found, return an empty string.
	} else {
	    return title.getText();
	} 
    } 

    /**
     * @see org.enhydra.apache.html.dom.HTMLDocumentImpl#setTitle
     */
    public synchronized void setTitle(String newTitle) {
	// Enhydra modified: Original Xerces code used getElementsByTagName()
	// to find the title.  We assume it' a direct child of HEAD (although
	// more error checking might be better).
	HTMLElement head = getHead();
	HTMLTitleElement title = 
	    (HTMLTitleElement)getDirectChildElement("title", head);

	if (title == null) {
	    title = new XHTMLTitleElementImpl(this, head.getNamespaceURI(),
                                              "title");
	} 
	title.setText(newTitle);
    } 

    /**
     * Find a BODY or FRAMESET element.
     */
    private HTMLElement findBody(Element html) {
	HTMLElement body = (HTMLElement)getDirectChildElement("body", html);
	if (body == null) {
	    body = (HTMLElement)getDirectChildElement("frameset", html);
	} 

	return body;
    } 

    /**
     * @see org.enhydra.apache.html.dom.HTMLDocumentImpl#getBody
     */
    public synchronized HTMLElement getBody() {
	// Enhydra modified: Original Xerces code tried to reorder nodes to
	// make things right, which moved around comments to weird locations.
	// Throwing an error would be more appropriate, but we were afraid of
	// breaking existing code, so just get the node.
	// Find BODY or FRAMESET
	Element html = getDocumentElement();
	HTMLElement body = findBody(html);

	if (body == null) {
	    // Create new body, and place it a the end of the HTML element.
	    body = new XHTMLBodyElementImpl(this, html.getNamespaceURI(),
                                            "body");
	    html.appendChild(body);
	} 

	return body;
    } 

    /**
     * @see org.enhydra.apache.html.dom.HTMLDocumentImpl#setBody
     */
    public synchronized void setBody(HTMLElement newBody) {
	// Enhydra modified: Original Xerces code tried to reorder nodes to
	// make things right, which moved around comments to weird locations.
	// Throwing an error would be more appropriate, but we were afraid of
	// breaking existing code, so just get the node.
	// Find BODY or FRAMESET
	Element     html = getDocumentElement();
	HTMLElement body = findBody(html);

	if (body == null) {
	    html.appendChild(newBody);
	} else {
	    html.replaceChild(newBody, body);
	} 
    } 

    /**
     * @see org.enhydra.apache.html.dom.HTMLDocumentImpl#getElementById
     */
    public synchronized Element getElementById(String elementId) {
	return getElementById(elementId, this);
    } 

    /**
     * @see org.enhydra.apache.html.dom.HTMLDocumentImpl#getElementsByName
     */
    public NodeList getElementsByName(String elementName) {
	return new NameNodeListImpl(this, elementName);
    } 

    /**
     * @see org.enhydra.apache.html.dom.HTMLDocumentImpl#getElementsByTagName
     */
    public final NodeList getElementsByTagName(String tagName) {
	return super.getElementsByTagName(tagName);
    } 

    /**
     * @see org.enhydra.apache.html.dom.HTMLDocumentImpl#getElementsByTagNameNS
     */
    public final NodeList getElementsByTagNameNS(String namespaceURI, 
                                                 String localName) {
	if (namespaceURI != null && namespaceURI.length() > 0) {
	    return super.getElementsByTagNameNS(namespaceURI, 
						localName);
	} else {
	    return super.getElementsByTagName(localName);
	}
    } 

    /**
     * @see org.enhydra.apache.html.dom.HTMLDocumentImpl#createElementNS
     */
    public Element createElementNS(String namespaceURI, 
				   String qualifiedName) {
        // FIXME: should be a common method for doing this
        int index = qualifiedName.indexOf(':');
        String tagName;
        if (index < 0) {
            tagName = qualifiedName;
        } else {
            tagName = qualifiedName.substring(index+1);
        }
        Class elemClass = (Class)fElementTypes.get(tagName);
        if (elemClass != null) {
            try	{
                Constructor cnst = elemClass.getConstructor(fElemConstructorSig);
                return (Element)cnst.newInstance(new Object[] {this, namespaceURI, qualifiedName});
            } catch (Exception except) {
                // Need more specific error..
                throw new XMLCError("failed to construct element for \""
                                    + qualifiedName + "\"", except);
            }
        } else {
            return new XHTMLElementImpl(this, namespaceURI, qualifiedName);
        }
    } 

    /**
     * @see org.enhydra.apache.html.dom.HTMLDocumentImpl#createElement
     */
    public Element createElement(String tagName) throws DOMException {
        return createElementNS(null, tagName);
    } 

    /**
     * @see org.enhydra.apache.html.dom.HTMLDocumentImpl#getReferrer
     */
    public String getReferrer() {
	// Information not available on server side.
	return null;
    } 

    /**
     * @see org.enhydra.apache.html.dom.HTMLDocumentImpl#getDomain
     */
    public String getDomain() {
	// Information not available on server side.
	return null;
    } 

    /**
     * @see org.enhydra.apache.html.dom.HTMLDocumentImpl#getURL
     */
    public String getURL() {
	// Information not available on server side.
	return null;
    } 

    /**
     * @see org.enhydra.apache.html.dom.HTMLDocumentImpl#getCookie
     */
    public String getCookie() {
	// Information not available on server side.
	return null;
    } 

    /**
     * @see org.enhydra.apache.html.dom.HTMLDocumentImpl#setCookie
     */
    public void setCookie(String cookie) {
	// Information not available on server side.
    } 

    /**
     * @see org.enhydra.apache.html.dom.HTMLDocumentImpl#getImages
     */
    public HTMLCollection getImages() {
	// For more information see HTMLCollection#collectionMatch
	if (fImages == null) {
	    fImages = new XHTMLCollectionImpl(getBody(), 
					      XHTMLCollectionImpl.IMAGE);
	} 

	return fImages;
    } 

    /**
     * @see org.enhydra.apache.html.dom.HTMLDocumentImpl#getApplets
     */
    public HTMLCollection getApplets() {
	// For more information see HTMLCollection#collectionMatch
	if (fApplets == null) {
	    fApplets = new XHTMLCollectionImpl(getBody(), 
					       XHTMLCollectionImpl.APPLET);
	} 

	return fApplets;
    } 

    /**
     * @see org.enhydra.apache.html.dom.HTMLDocumentImpl#getLinks
     */
    public HTMLCollection getLinks() {
	// For more information see HTMLCollection#collectionMatch
	if (fLinks == null) {
	    fLinks = new XHTMLCollectionImpl(getBody(), 
					     XHTMLCollectionImpl.LINK);
	} 

	return fLinks;
    } 

    /**
     * @see org.enhydra.apache.html.dom.HTMLDocumentImpl#getForms
     */
    public HTMLCollection getForms() {
	// For more information see HTMLCollection#collectionMatch
	if (fForms == null) {
	    fForms = new XHTMLCollectionImpl(getBody(), 
					     XHTMLCollectionImpl.FORM);
	} 

	return fForms;
    } 

    /**
     * @see org.enhydra.apache.html.dom.HTMLDocumentImpl#getAnchors
     */
    public HTMLCollection getAnchors() {
	// For more information see HTMLCollection#collectionMatch
	if (fAnchors == null) {
	    fAnchors = new XHTMLCollectionImpl(getBody(), 
					       XHTMLCollectionImpl.ANCHOR);
	} 

	return fAnchors;
    } 

    /**
     * @see org.enhydra.apache.html.dom.HTMLDocumentImpl#optn
     */
    public void open() {
	// When called an in-memory is prepared. The document tree is still
	// accessible the old way, until this writer is closed.
	if (fWriter == null) {
	    fWriter = new StringWriter();
	} 
    } 

    /**
     * @see org.enhydra.apache.html.dom.HTMLDocumentImpl#close
     */
    public void close() {
	// ! NOT IMPLEMENTED, REQUIRES PARSER !
	if (fWriter != null) {
	    fWriter = null;
	} 
    } 

    /**
     * @see org.enhydra.apache.html.dom.HTMLDocumentImpl#write
     */
    public void write(String text) {
	// Write a string into the in-memory writer.
	if (fWriter != null) {
	    fWriter.write(text);
	} 
    } 

    /**
     * @see org.enhydra.apache.html.dom.HTMLDocumentImpl#writeln
     */
    public void writeln(String text) {
	// Write a line into the in-memory writer.
	if (fWriter != null) {
	    fWriter.write(text + "\n");
	} 
    } 

    /**
     * @see org.enhydra.apache.html.dom.HTMLDocumentImpl#cloneNode
     */
    public Node cloneNode(boolean deep) {
	XHTMLDocumentImpl clone;
	NodeImpl node;

	clone = new XHTMLDocumentImpl();
	if (deep) {
	    node = (NodeImpl) getFirstChild();

	    while (node != null) {
		clone.appendChild(clone.importNode(node, true));
		node = (NodeImpl) node.getNextSibling();
	    } 
	} 

	return clone;
    } 

    /**
     * overload in order to return the correct dom implementation for XHTML
     * @see org.enhydra.apache.xerces.dom.DocumentImpl#getImplementation
     */
    public DOMImplementation getImplementation() {
        return XHTMLDOMImplementationImpl.getDOMImplementation();
    }

    /**
     * Recursive method retreives an element by its id attribute.
     * Called by {@link #getElementById(String)}.
     * 
     * @param elementId The id value to look for
     * @return The node in which to look for
     */
    private Element getElementById(String elementId, Node node) {
	Node child;
	Element result;

	child = node.getFirstChild();

	while (child != null) {
	    if (child instanceof Element) {
		if (elementId.equals(((Element) child).getAttribute("id"))) {
		    return (Element) child;
		} 
		result = getElementById(elementId, child);
		if (result != null) {
		    return result;
		} 
	    } 
	    child = child.getNextSibling();
	} 

	return null;
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy