Package org.apache.xindice.xml.dom

Source Code of org.apache.xindice.xml.dom.DocumentImpl

/*
* Copyright 1999-2004 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* CVS $Id: DocumentImpl.java,v 1.16 2004/02/24 15:32:27 vgritsenko Exp $
*/

package org.apache.xindice.xml.dom;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.xindice.util.XindiceException;
import org.apache.xindice.xml.NodeSource;
import org.apache.xindice.xml.SymbolTable;
import org.apache.xindice.xml.dom.traversal.TreeWalkerImpl;

import org.w3c.dom.Attr;
import org.w3c.dom.CDATASection;
import org.w3c.dom.Comment;
import org.w3c.dom.DOMException;
import org.w3c.dom.DOMImplementation;
import org.w3c.dom.Document;
import org.w3c.dom.DocumentFragment;
import org.w3c.dom.DocumentType;
import org.w3c.dom.Element;
import org.w3c.dom.EntityReference;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.ProcessingInstruction;
import org.w3c.dom.Text;
import org.w3c.dom.traversal.DocumentTraversal;
import org.w3c.dom.traversal.NodeFilter;
import org.w3c.dom.traversal.NodeIterator;
import org.w3c.dom.traversal.TreeWalker;

import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

/**
* DocumentImpl
*
* @version CVS $Revision: 1.16 $, $Date: 2004/02/24 15:32:27 $
*/
public final class DocumentImpl extends ContainerNodeImpl implements CompressedDocument, DBDocument, DocumentTraversal {

    private static final Log log = LogFactory.getLog(DocumentImpl.class);

    private DocumentType docType = null;
    private String version = null;
    private String actualEncoding = null;
    private String encoding = null;
    private boolean standalone = false;
    private boolean strictErrorChecking = false;
    private SymbolTable symbols = null;
    private boolean readOnly = false;


    public DocumentImpl() {
        super(null, true);
    }

    public DocumentImpl(byte[] data, int pos, int len) {
        super(null, data, pos, len);
    }

    public DocumentImpl(byte[] data) {
        this(data, 0, data.length);
    }

    public DocumentImpl(byte[] data, SymbolTable symbols, NodeSource source) {
        this(data);
        this.symbols = symbols;
        this.source = source;
    }

    public DocumentImpl(Document doc) throws XindiceException {
        super(null, true);

        boolean compress = true;

        if (doc instanceof CompressedDocument) {
            CompressedDocument c = (CompressedDocument) doc;
            symbols = c.getSymbols();
            if (!c.isDirty()) {
                data = c.getDataBytes();
                pos = c.getDataPos();
                len = c.getDataLen();
                compress = false;
            }
        }

        if (compress) {
            if (symbols == null) {
                symbols = new SymbolTable();
            }
            data = DOMCompressor.Compress(doc, symbols);
            pos = 0;
            len = data.length;
        }

        if (doc instanceof DBDocument) {
            DBDocument d = (DBDocument) doc;
            source = d.getSource();
        }
    }

    public boolean isReadOnly() {
        return readOnly;
    }

    protected void checkLoaded() {
        if (loaded) {
            return;
        } else {
            loaded = true;
        }

        try {
            if (data != null) {
                loadChildren(symbols);
            }
        } catch (Exception e) {
            if (log.isWarnEnabled()) {
                log.warn("ignored exception", e);
            }
        }
    }

    public boolean isCaching() {
        String cache = DBDocument.CACHE;

        int size = childNodes.getLength();
        for (int i = 0; i < size; i++) {
            Node n = childNodes.item(i);
            if (n.getNodeType() == Node.PROCESSING_INSTRUCTION_NODE && n.getNodeName().equals(CACHE_CONTROL)) {
                cache = n.getNodeValue().trim();
                break;
            }
        }

        return (cache != null && cache.equals(CACHE));
    }

    public void setCaching(boolean caching) {
        int size = childNodes.getLength();
        for (int i = 0; i < size; i++) {
            Node n = childNodes.item(i);
            if (n.getNodeType() == Node.PROCESSING_INSTRUCTION_NODE && n.getNodeName().equals(CACHE_CONTROL)) {
                n.setNodeValue(caching ? CACHE : NOCACHE);
                return;
            }
        }

        ProcessingInstruction pi = createProcessingInstruction(CACHE_CONTROL, caching ? CACHE : NOCACHE);
        insertBefore(pi, getDocumentElement());
    }

    public SymbolTable getSymbols() {
        return symbols;
    }

    public void setSymbols(SymbolTable symbols) {
        this.symbols = symbols;
    }

    public void expandSource() {
        ElementImpl e = (ElementImpl) getDocumentElement();
        if (e != null) {
            e.expandSource();
        }
    }

    public Node getNodeAtPos(int pos) {
        return null; // TODO: This
    }

    public short getNodeType() {
        return Node.DOCUMENT_NODE;
    }

    public String getNodeName() {
        return "#document";
    }

    /**
     * The Document Type Declaration (see <code>DocumentType</code>) associated
     * with  this document. For HTML documents as well as XML documents without
     * a document type declaration this returns <code>null</code>. The DOM Level
     *  1 does not support editing the Document Type Declaration, therefore
     * <code>docType</code> cannot be altered in any way.
     */
    public DocumentType getDoctype() {
        return docType;
    }

    public void setDoctype(DocumentType docType) {
        this.docType = docType;
    }

    /**
     * The <code>DOMImplementation</code> object that handles this document. A
     * DOM application may use objects from multiple  implementations.
     */
    public DOMImplementation getImplementation() {
        return DOMImplementationImpl.getInstance();
    }

    /**
     * Creates a <code>Text</code> node given the specified string.
     * @param data The data for the node.
     * @return The new <code>Text</code> object.
     */
    public Text createTextNode(String data) {
        return new TextImpl(this, data);
    }

    /**
     * This is a convenience attribute that allows direct access to the child
     * node that is the root element of  the document. For HTML documents, this
     * is the element with the tagName "HTML".
     */
    public Element getDocumentElement() {
        checkLoaded();
        Iterator enum = childNodes.iterator();
        while (enum.hasNext()) {
            Node node = (Node) enum.next();
            if (node.getNodeType() == Node.ELEMENT_NODE) {
                return (Element) node;
            }
        }
        return null;
    }

    /**
     * Creates a <code>CDATASection</code> node whose value  is the specified
     * string.
     * @param data The data for the <code>CDATASection</code> contents.
     * @return The new <code>CDATASection</code> object.
     * @exception DOMException
     *   NOT_SUPPORTED_ERR: Raised if this document is an HTML document.
     */
    public CDATASection createCDATASection(String data) throws DOMException {
        return new CDATASectionImpl(this, data);
    }

    /**
     * Creates an element of the type specified. Note that the instance returned
     * implements the Element interface, so attributes can be specified
     * directly  on the returned object.
     * @param tagName The name of the element type to instantiate. For XML, this
     *   is case-sensitive. For HTML, the  <code>tagName</code> parameter may
     *   be provided in any case,  but it must be mapped to the canonical
     *   uppercase form by  the DOM implementation.
     * @return A new <code>Element</code> object.
     * @exception DOMException
     *   INVALID_CHARACTER_ERR: Raised if the specified name contains an
     *   invalid character.
     */
    public Element createElement(String tagName) throws DOMException {
        return new ElementImpl(this, tagName);
    }

    /**
     * Creates an empty <code>DocumentFragment</code> object.
     * @return A new <code>DocumentFragment</code>.
     */
    public DocumentFragment createDocumentFragment() {
        return new DocumentFragmentImpl(this);
    }

    /**
     * Creates an <code>Attr</code> of the given name. Note that the
     * <code>Attr</code> instance can then be set on an <code>Element</code>
     * using the <code>setAttribute</code> method.
     * @param name The name of the attribute.
     * @return A new <code>Attr</code> object.
     * @exception DOMException
     *   INVALID_CHARACTER_ERR: Raised if the specified name contains an
     *   invalid character.
     */
    public Attr createAttribute(String name) throws DOMException {
        return new AttrImpl(this, name);
    }

    /**
     * Creates a <code>Comment</code> node given the specified string.
     * @param data The data for the node.
     * @return The new <code>Comment</code> object.
     */
    public Comment createComment(String data) {
        return new CommentImpl(this, data);
    }

    /**
     * Creates a <code>ProcessingInstruction</code> node given the specified
     * name and data strings.
     * @param target The target part of the processing instruction.
     * @param data The data for the node.
     * @return The new <code>ProcessingInstruction</code> object.
     * @exception DOMException
     *   INVALID_CHARACTER_ERR: Raised if an invalid character is specified.
     *   <br>NOT_SUPPORTED_ERR: Raised if this document is an HTML document.
     */
    public ProcessingInstruction createProcessingInstruction(String target, String data) throws DOMException {
        return new ProcessingInstructionImpl(this, target, data);
    }

    /**
     * Creates an EntityReference object.
     * @param name The name of the entity to reference.
     * @return The new <code>EntityReference</code> object.
     * @exception DOMException
     *   INVALID_CHARACTER_ERR: Raised if the specified name contains an
     *   invalid character.
     *   <br>NOT_SUPPORTED_ERR: Raised if this document is an HTML document.
     */
    public EntityReference createEntityReference(String name) throws DOMException {
        return new EntityReferenceImpl(this, name);
    }

    private void importNamespaces(Node source, Node target) {
        if (target.getNodeType() == Node.ELEMENT_NODE) {
            // Retrieve Namespace definitions in scope
            Set set = new HashSet();
            Node n = source;
            Element elem = (Element) target;
            while (n != null) {
                NamedNodeMap nm = n.getAttributes();
                for (int i = 0; i < nm.getLength(); i++) {
                    Attr a = (Attr) nm.item(i);
                    String name = a.getNodeName();
                    if ((name.startsWith("xmlns:") || name.equals("xmlns")) && !set.contains(name)) {
                        set.add(name);
                        elem.setAttribute(name, a.getValue());
                    }
                }
                n = n.getParentNode();
                if (n.getNodeType() == DOCUMENT_NODE || n.getNodeType() == DOCUMENT_FRAGMENT_NODE) {
                    n = null;
                }
            }
        }
    }

    public Node importNode(Node importedNode, boolean deep) {
    return importNode(importedNode, deep, true);
  }

  private Node importNode(Node importedNode, boolean deep, boolean importNamespaces) {
        try {
            // If we're a Xindice DOM Node and share the same symbol table,
            // then we're golden
            if (importedNode instanceof NodeImpl) {
                NodeImpl impl = (NodeImpl) importedNode;
                DocumentImpl docImpl = (DocumentImpl) impl.getOwnerDocument();
                if (docImpl.getSymbols() != null && (docImpl.getSymbols() == symbols)) {
                    NodeImpl clone = (NodeImpl) impl.cloneNode(deep);
                    clone.setParentNode(this);
          if (importNamespaces)
          {
            importNamespaces(importedNode, clone);
          }
                    return clone;
                }
            }

            // Crap, we have to do a full graph copy
            Node result = null;
            switch (importedNode.getNodeType()) {
                case Node.ATTRIBUTE_NODE:
                    result = createAttribute(importedNode.getNodeName());
                    break;

                case Node.CDATA_SECTION_NODE:
                    result = createCDATASection(importedNode.getNodeValue());
                    break;

                case Node.COMMENT_NODE:
                    result = createComment(importedNode.getNodeValue());
                    break;

                case Node.ELEMENT_NODE:
                    Element selem = (Element) importedNode;
                    Element elem = createElement(selem.getTagName());
                    NamedNodeMap attrs = selem.getAttributes();
                    int size = attrs.getLength();
                    for (int i = 0; i < size; i++) {
                        Attr a = (Attr) attrs.item(i);
                        Attr ai = createAttribute(a.getName());
                        ai.setValue(a.getValue());
                        elem.setAttributeNode(ai);
                    }
                    result = elem;
          if (importNamespaces)
          {
            importNamespaces(importedNode, result);
          }
                    break;

                case Node.ENTITY_REFERENCE_NODE:
                    result = createEntityReference(importedNode.getNodeValue());
                    break;

                case Node.PROCESSING_INSTRUCTION_NODE:
                    result = createProcessingInstruction(importedNode.getNodeName(), importedNode.getNodeValue());
                    break;

                case Node.TEXT_NODE:
                    result = createTextNode(importedNode.getNodeValue());
                    break;

                default :
            }

            if (deep && result != null) {
                NodeList list = importedNode.getChildNodes();
                int size = list.getLength();
                for (int i = 0; i < size; i++) {
                    Node n = list.item(i);
                    result.appendChild(importNode(n, deep, false));
                }
            }

            return result;
        } catch (Exception e) {
            if (log.isWarnEnabled()) {
                log.warn("ignored exception", e);
            }
            return null;
        }
    }

    public Element createElementNS(String namespaceURI, String qualifiedName) {
        return new ElementImpl(this, qualifiedName);
    }

    public Attr createAttributeNS(String namespaceURI, String qualifiedName) {
        return new AttrImpl(this, qualifiedName);
    }

    public NodeIterator createNodeIterator(Node root, int whatToShow, NodeFilter filter, boolean entityReferenceExpansion) throws DOMException {
        return new TreeWalkerImpl(root, whatToShow, filter, entityReferenceExpansion);
    }

    public TreeWalker createTreeWalker(Node root, int whatToShow, NodeFilter filter, boolean entityReferenceExpansion) throws DOMException {
        return new TreeWalkerImpl(root, whatToShow, filter, entityReferenceExpansion);
    }

    // DOM Level 3 Stuff

    public Node adoptNode(Node src) {
        // If we're a Xindice DOM Node and share the same symbol table
        // or the adopted node has no symbol table, then we're golden
        if (src instanceof NodeImpl) {
            NodeImpl impl = (NodeImpl) src;
            DocumentImpl docImpl = (DocumentImpl) impl.getOwnerDocument();
            if (docImpl.getSymbols() == null || docImpl.getSymbols() == symbols) {
                impl.getParentNode().removeChild(impl);
                impl.setParentNode(this);
                return impl;
            }
        }
        return importNode(src, true);
    }

    public String getActualEncoding() {
        checkLoaded();
        return actualEncoding;
    }

    public void setActualEncoding(String actualEncoding) {
        checkReadOnly();
        checkLoaded();
        this.actualEncoding = actualEncoding;
    }

    public String getEncoding() {
        checkLoaded();
        return encoding;
    }

    public void setEncoding(String encoding) {
        checkReadOnly();
        checkLoaded();
        this.encoding = encoding;
    }

    public String getVersion() {
        checkLoaded();
        return version;
    }

    public void setVersion(String version) {
        checkReadOnly();
        checkLoaded();
        this.version = version;
    }

    public boolean getStandalone() {
        checkLoaded();
        return standalone;
    }

    public void setStandalone(boolean standalone) {
        checkReadOnly();
        checkLoaded();
        this.standalone = standalone;
    }

    public boolean getStrictErrorChecking() {
        checkLoaded();
        return strictErrorChecking;
    }

    public void setStrictErrorChecking(boolean strictErrorChecking) {
        checkReadOnly();
        checkLoaded();
        this.strictErrorChecking = strictErrorChecking;
    }
}
TOP

Related Classes of org.apache.xindice.xml.dom.DocumentImpl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.