/* * Copyright (c) 1998-2011 Caucho Technology -- all rights reserved * * This file is part of Resin(R) Open Source * * Each copy or derived work must preserve the copyright notice and this * notice unmodified. * * Resin Open Source is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * Resin Open Source is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty * of NON-INFRINGEMENT. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with Resin Open Source; if not, write to the * Free SoftwareFoundation, Inc. * 59 Temple Place, Suite 330 * Boston, MA 02111-1307 USA * * @author Scott Ferguson */ package com.caucho.xml; // import com.caucho.xpath.pattern.NodeListIterator; import org.w3c.dom.DOMException; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import java.util.Iterator; /** * QNode represents any node that can have children. */ public abstract class QNode extends QAbstractNode { protected QAbstractNode _firstChild; protected QAbstractNode _lastChild; protected QNode() { } protected QNode(QDocument owner) { super(owner); } public String getNodeValue() { return null; } public void setNodeValue(String value) {} /** * Returns a node list of the children. */ public NodeList getChildNodes() { return new ChildNodeList(); } public Node getFirstChild() { return _firstChild; } public Node getLastChild() { return _lastChild; } public Node getPreviousSibling() { return _previous; } public Node getNextSibling() { return _next; } public NamedNodeMap getAttributes() { return null; } public Node insertBefore(Node newChild, Node refChild) throws DOMException { QAbstractNode qNewChild = (QAbstractNode) newChild; QAbstractNode qRefChild = (QAbstractNode) refChild; if (qNewChild._owner != _owner && qNewChild._owner != this) throw new QDOMException(DOMException.WRONG_DOCUMENT_ERR, "insertBefore new child from wrong document"); qNewChild.remove(); if (qRefChild != null && qRefChild._parent != this) throw new QDOMException(DOMException.NOT_FOUND_ERR, "insertBefore has no such child"); if (qNewChild instanceof QDocumentFragment) { QDocumentFragment frag = (QDocumentFragment) qNewChild; QAbstractNode first = frag._firstChild; QAbstractNode next = null; for (QAbstractNode ptr = first; ptr != null; ptr = next) { next = ptr._next; insertBefore(ptr, refChild); } return first; } qNewChild._parent = this; if (refChild == null) { if (_firstChild == null) { qNewChild._previous = null; qNewChild._next = null; _firstChild = _lastChild = qNewChild; } else { _lastChild._next = qNewChild; qNewChild._previous = _lastChild; _lastChild = qNewChild; qNewChild._next = null; } return qNewChild; } qNewChild._previous = qRefChild._previous; qNewChild._next = qRefChild; if (qRefChild._previous == null) _firstChild = qNewChild; else qRefChild._previous._next = qNewChild; qRefChild._previous = qNewChild; return qNewChild; } public Node replaceChild(Node newChild, Node refChild) throws DOMException { QAbstractNode qNewChild = (QAbstractNode) newChild; QAbstractNode qRefChild = (QAbstractNode) refChild; if (qRefChild == null || qRefChild._parent != this) throw new QDOMException(DOMException.NOT_FOUND_ERR, "ref is not child"); if (qNewChild == null || qNewChild._owner != _owner) throw new QDOMException(DOMException.WRONG_DOCUMENT_ERR, "wrong document"); if (_owner != null) _owner._changeCount++; qNewChild._previous = qRefChild._previous; qNewChild._next = qRefChild._next; qNewChild._parent = this; if (qNewChild._previous == null) _firstChild = qNewChild; else qNewChild._previous._next = qNewChild; if (qNewChild._next == null) _lastChild = qNewChild; else qNewChild._next._previous = qNewChild; qRefChild._previous = null; qRefChild._next = null; qRefChild._parent = null; return qRefChild; } public Node removeChild(Node oldChild) throws DOMException { QAbstractNode qOldChild = (QAbstractNode) oldChild; if (qOldChild != null && qOldChild._parent != this) { throw new QDOMException(DOMException.NOT_FOUND_ERR, "removeChild has no such child"); } if (_owner != null) _owner._changeCount++; if (qOldChild._previous == null) _firstChild = qOldChild._next; else qOldChild._previous._next = qOldChild._next; if (qOldChild._next == null) _lastChild = qOldChild._previous; else qOldChild._next._previous = qOldChild._previous; qOldChild._parent = null; qOldChild._next = null; qOldChild._previous = null; return qOldChild; } private static void setOwner(QAbstractNode node, QDocument owner) { if (node._owner == null) { node._owner = owner; String namespace = node.getNamespaceURI(); if (namespace != "") owner.addNamespace(node.getPrefix(), namespace); for (QAbstractNode child = (QAbstractNode) node.getFirstChild(); child != null; child = (QAbstractNode) child.getNextSibling()) { setOwner(child, owner); } } } public Node appendChild(Node newNode) throws DOMException { QAbstractNode qNewNode = (QAbstractNode) newNode; setOwner(qNewNode, _owner); if (qNewNode._owner != _owner && qNewNode._owner != this) { throw new QDOMException(DOMException.WRONG_DOCUMENT_ERR, "can't appendChild from different document"); } qNewNode.remove(); if (qNewNode instanceof QDocumentFragment) { QDocumentFragment frag = (QDocumentFragment) qNewNode; QAbstractNode first = frag._firstChild; QAbstractNode next = null; for (QAbstractNode ptr = first; ptr != null; ptr = next) { next = ptr._next; appendChild(ptr); } return first; } qNewNode._parent = this; qNewNode._next = null; qNewNode._previous = _lastChild; if (_lastChild == null) { _lastChild = qNewNode; _firstChild = qNewNode; } else { _lastChild._next = qNewNode; _lastChild = qNewNode; } return qNewNode; } public boolean hasChildNodes() { return _firstChild != null; } public void setTextContent(String content) { QText text = new QText(content); text._owner = _owner; _firstChild = _lastChild = text; } public void normalize() { } public boolean checkValid() throws Exception { if (! super.checkValid()) throw new Exception("super bad: " + this); if (_firstChild != null && _firstChild._previous != null) throw new Exception("first child bad: " + this); if (_lastChild != null && _lastChild._next != null) throw new Exception("last child bad:" + this); QAbstractNode ptr = _firstChild; for (; ptr != null; ptr = ptr._next) { if (ptr._parent != this) throw new Exception("child parent bad:" + this + " " + ptr); if (ptr._owner != _owner && ptr._owner != this) throw new Exception("child owner bad:" + this + " " + ptr + " " + ptr._owner + " " + _owner); if (ptr._next != null && ptr._next._previous != ptr) throw new Exception("child links bad:" + this + " " + ptr); } ptr = _lastChild; for (; ptr != null; ptr = ptr._previous) { if (ptr._parent != this) throw new Exception("child parent bad:" + this + " " + ptr); if (ptr._owner != _owner && ptr._owner != this) throw new Exception("child owner bad:" + this + " " + ptr); if (ptr._previous != null && ptr._previous._next != ptr) throw new Exception("child links bad:" + this + " " + ptr); } return true; } public QAbstractNode getNextPreorder() { if (_firstChild != null) return _firstChild; else if (_next != null) return _next; for (QNode ptr = _parent; ptr != null; ptr = ptr._parent) { if (ptr._next != null) return ptr._next; } return null; } public boolean equals(Object arg) { return this == arg; } public boolean equals(Node arg, boolean deep) { return this == arg; } // NodeList methods public class ChildNodeList implements NodeList { /** * Returns the child with the given index. */ public Node item(int index) { QAbstractNode ptr = _firstChild; for (; ptr != null && index > 0; index--) { ptr = ptr._next; } return ptr; } /** * Returns the number of children. */ public int getLength() { int index = 0; for (QAbstractNode ptr = _firstChild; ptr != null; ptr = ptr._next) index++; return index; } /* // for quercus public Iterator<Node> iterator() { return new NodeListIterator(null, this); } */ } }