
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