/*
* eXist Open Source Native XML Database
* Copyright (C) 2001-2007 The eXist Project
* http://exist-db.org
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program 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. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* $Id$
*/
package org.exist.memtree;
import org.exist.Namespaces;
import org.exist.dom.NamedNodeMapImpl;
import org.exist.dom.NodeListImpl;
import org.exist.dom.QName;
import org.exist.dom.QNameable;
import org.exist.xquery.NodeTest;
import org.exist.xquery.XPathException;
import org.exist.xquery.value.Sequence;
import org.exist.xquery.value.Type;
import org.exist.xquery.value.ValueSequence;
import org.w3c.dom.Attr;
import org.w3c.dom.DOMException;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.Text;
import org.w3c.dom.TypeInfo;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
public class ElementImpl extends NodeImpl implements Element, QNameable {
public ElementImpl(DocumentImpl doc, int nodeNumber) {
super(doc, nodeNumber);
}
/* (non-Javadoc)
* @see org.w3c.dom.Element#getTagName()
*/
public String getTagName() {
return getNodeName();
}
public QName getQName() {
return document.nodeName[nodeNumber];
}
/* (non-Javadoc)
* @see org.w3c.dom.Node#hasChildNodes()
*/
public boolean hasChildNodes() {
return nodeNumber + 1 < document.size
&& document.treeLevel[nodeNumber + 1] > document.treeLevel[nodeNumber];
}
/* (non-Javadoc)
* @see org.w3c.dom.Node#getFirstChild()
*/
public Node getFirstChild() {
short level = document.treeLevel[nodeNumber];
int nextNode = nodeNumber + 1;
if (nextNode < document.size && document.treeLevel[nextNode] > level) {
return document.getNode(nextNode);
} else
return null;
}
/* (non-Javadoc)
* @see org.w3c.dom.Node#getChildNodes()
*/
public NodeList getChildNodes() {
NodeListImpl nl = new NodeListImpl();
int nextNode = document.getFirstChildFor(nodeNumber);
while (nextNode > nodeNumber) {
Node n = document.getNode(nextNode);
nl.add(n);
nextNode = document.next[nextNode];
}
return nl;
}
public int getChildCount() {
return document.getChildCountFor(nodeNumber);
}
/* (non-Javadoc)
* @see org.w3c.dom.Node#getNamespaceURI()
*/
public String getNamespaceURI() {
return getQName().getNamespaceURI();
}
/* (non-Javadoc)
* @see org.w3c.dom.Node#getPrefix()
*/
public String getPrefix() {
return getQName().getPrefix();
}
/* (non-Javadoc)
* @see org.w3c.dom.Node#getLocalName()
*/
public String getLocalName() {
return getQName().getLocalName();
}
/* (non-Javadoc)
* @see org.w3c.dom.Node#hasAttributes()
*/
public boolean hasAttributes() {
return document.alpha[nodeNumber] > -1 || document.alphaLen[nodeNumber] > -1;
}
/* (non-Javadoc)
* @see org.w3c.dom.Element#getAttribute(java.lang.String)
*/
public String getAttribute(String name) {
int attr = document.alpha[nodeNumber];
if (-1 < attr) {
while (attr < document.nextAttr
&& document.attrParent[attr] == nodeNumber) {
QName attrQName = document.attrName[attr];
if (attrQName.getStringValue().equals(name))
return document.attrValue[attr];
++attr;
}
}
if(name.startsWith("xmlns:")) {
int ns = document.alphaLen[nodeNumber];
if (-1 < ns) {
while (ns < document.nextNamespace
&& document.namespaceParent[ns] == nodeNumber) {
QName nsQName = document.namespaceCode[ns];
if (nsQName.getStringValue().equals(name))
return nsQName.getNamespaceURI();
++ns;
}
}
}
return null;
}
/* (non-Javadoc)
* @see org.w3c.dom.Element#setAttribute(java.lang.String, java.lang.String)
*/
public void setAttribute(String arg0, String arg1) throws DOMException {
// TODO Auto-generated method stub
}
/* (non-Javadoc)
* @see org.w3c.dom.Element#removeAttribute(java.lang.String)
*/
public void removeAttribute(String arg0) throws DOMException {
// TODO Auto-generated method stub
}
public int getAttributesCount() {
return document.getAttributesCountFor(nodeNumber)+document.getNamespacesCountFor(nodeNumber);
}
/* (non-Javadoc)
* @see org.w3c.dom.Node#getAttributes()
*/
public NamedNodeMap getAttributes() {
NamedNodeMapImpl map = new NamedNodeMapImpl();
int attr = document.alpha[nodeNumber];
if(-1 < attr) {
while (attr < document.nextAttr
&& document.attrParent[attr] == nodeNumber) {
map.add(new AttributeImpl(document, attr));
++attr;
}
}
// add namespace declarations attached to this element
int ns = document.alphaLen[nodeNumber];
if (ns < 0)
return map;
while (ns < document.nextNamespace
&& document.namespaceParent[ns] == nodeNumber) {
NamespaceNode node = new NamespaceNode(document, ns);
map.add(node);
++ns;
}
return map;
}
/* (non-Javadoc)
* @see org.w3c.dom.Element#getAttributeNode(java.lang.String)
*/
public Attr getAttributeNode(String name) {
int attr = document.alpha[nodeNumber];
if (-1 < attr) {
while (attr < document.nextAttr
&& document.attrParent[attr] == nodeNumber) {
QName attrQName = document.attrName[attr];
if (attrQName.getStringValue().equals(name))
return new AttributeImpl(document, attr);
++attr;
}
}
if(name.startsWith("xmlns:")) {
int ns = document.alphaLen[nodeNumber];
if (-1 < ns) {
while (ns < document.nextNamespace
&& document.namespaceParent[ns] == nodeNumber) {
QName nsQName=document.namespaceCode[ns];
if (nsQName.getStringValue().equals(name))
return new NamespaceNode(document, ns);
++ns;
}
}
}
return null;
}
/* (non-Javadoc)
* @see org.w3c.dom.Element#setAttributeNode(org.w3c.dom.Attr)
*/
public Attr setAttributeNode(Attr arg0) throws DOMException {
// TODO Auto-generated method stub
return null;
}
/* (non-Javadoc)
* @see org.w3c.dom.Element#removeAttributeNode(org.w3c.dom.Attr)
*/
public Attr removeAttributeNode(Attr arg0) throws DOMException {
// TODO Auto-generated method stub
return null;
}
public void selectAttributes(NodeTest test, Sequence result) throws XPathException {
int attr = document.alpha[nodeNumber];
if (-1 < attr) {
while (attr < document.nextAttr
&& document.attrParent[attr] == nodeNumber) {
AttributeImpl attrib = new AttributeImpl(document, attr);
if (test.matches(attrib))
result.add(attrib);
++attr;
}
}
}
public void selectDescendantAttributes(NodeTest test, Sequence result) throws XPathException {
int treeLevel = document.treeLevel[nodeNumber];
int nextNode = nodeNumber;
NodeImpl n = document.getNode(nextNode);
n.selectAttributes(test, result);
while (++nextNode < document.size && document.treeLevel[nextNode] > treeLevel) {
n = document.getNode(nextNode);
if (n.getNodeType() == Node.ELEMENT_NODE)
n.selectAttributes(test, result);
}
}
public void selectChildren(NodeTest test, Sequence result) throws XPathException {
int nextNode = document.getFirstChildFor(nodeNumber);
while (nextNode > nodeNumber) {
NodeImpl n = document.getNode(nextNode);
if (test.matches(n))
result.add(n);
nextNode = document.next[nextNode];
}
}
public NodeImpl getFirstChild(NodeTest test) throws XPathException {
ValueSequence seq = new ValueSequence();
selectChildren(test, seq);
return seq.isEmpty() ? null : seq.get(0);
}
public void selectDescendants(boolean includeSelf, NodeTest test, Sequence result) throws XPathException {
int treeLevel = document.treeLevel[nodeNumber];
int nextNode = nodeNumber;
if (includeSelf) {
NodeImpl n = document.getNode(nextNode);
if (test.matches(n))
result.add(n);
}
while (++nextNode < document.size && document.treeLevel[nextNode] > treeLevel) {
NodeImpl n = document.getNode(nextNode);
if (test.matches(n))
result.add(n);
}
}
/* (non-Javadoc)
* @see org.w3c.dom.Element#getElementsByTagName(java.lang.String)
*/
public NodeList getElementsByTagName(String name) {
NodeListImpl nl = new NodeListImpl();
int nextNode = nodeNumber;
while (++nextNode < document.size) {
if (document.nodeKind[nextNode] == Node.ELEMENT_NODE) {
QName qn = document.nodeName[nextNode];
if(qn.getStringValue().equals(name))
nl.add(document.getNode(nextNode));
}
if (document.next[nextNode] <= nodeNumber) break;
}
return nl;
}
/* (non-Javadoc)
* @see org.w3c.dom.Element#getAttributeNS(java.lang.String, java.lang.String)
*/
public String getAttributeNS(String namespaceURI, String localName) {
int attr = document.alpha[nodeNumber];
if (-1 < attr) {
QName name;
while (attr < document.nextAttr
&& document.attrParent[attr] == nodeNumber) {
name = document.attrName[attr];
if (name.getLocalName().equals(localName)
&& name.getNamespaceURI().equals(namespaceURI))
return document.attrValue[attr];
++attr;
}
}
if(Namespaces.XMLNS_NS.equals(namespaceURI)) {
int ns = document.alphaLen[nodeNumber];
if (-1 < ns) {
while (ns < document.nextNamespace
&& document.namespaceParent[ns] == nodeNumber) {
QName nsQName=document.namespaceCode[ns];
if (nsQName.getLocalName().equals(localName))
return nsQName.getNamespaceURI();
++ns;
}
}
}
return null;
}
/* (non-Javadoc)
* @see org.w3c.dom.Element#setAttributeNS(java.lang.String, java.lang.String, java.lang.String)
*/
public void setAttributeNS(String arg0, String arg1, String arg2)
throws DOMException {
// TODO Auto-generated method stub
}
/* (non-Javadoc)
* @see org.w3c.dom.Element#removeAttributeNS(java.lang.String, java.lang.String)
*/
public void removeAttributeNS(String arg0, String arg1)
throws DOMException {
// TODO Auto-generated method stub
}
/* (non-Javadoc)
* @see org.w3c.dom.Element#getAttributeNodeNS(java.lang.String, java.lang.String)
*/
public Attr getAttributeNodeNS(String namespaceURI, String localName) {
int attr = document.alpha[nodeNumber];
if (-1 < attr) {
QName name;
while (attr < document.nextAttr
&& document.attrParent[attr] == nodeNumber) {
name = document.attrName[attr];
if (name.getLocalName().equals(localName)
&& name.getNamespaceURI().equals(namespaceURI))
return new AttributeImpl(document, attr);
++attr;
}
}
if(Namespaces.XMLNS_NS.equals(namespaceURI)) {
int ns = document.alphaLen[nodeNumber];
if (-1 < ns) {
while (ns < document.nextNamespace
&& document.namespaceParent[ns] == nodeNumber) {
QName nsQName=document.namespaceCode[ns];
if (nsQName.getLocalName().equals(localName))
return new NamespaceNode(document, ns);
++ns;
}
}
}
return null;
}
/* (non-Javadoc)
* @see org.w3c.dom.Element#setAttributeNodeNS(org.w3c.dom.Attr)
*/
public Attr setAttributeNodeNS(Attr arg0) throws DOMException {
// TODO Auto-generated method stub
return null;
}
/* (non-Javadoc)
* @see org.w3c.dom.Element#getElementsByTagNameNS(java.lang.String, java.lang.String)
*/
public NodeList getElementsByTagNameNS(String namespaceURI, String name) {
QName qname = new QName(name, namespaceURI);
NodeListImpl nl = new NodeListImpl();
int nextNode = nodeNumber;
while (++nextNode < document.size) {
if (document.nodeKind[nextNode] == Node.ELEMENT_NODE) {
QName qn = document.nodeName[nextNode];
if(qname.compareTo(qn) == 0)
nl.add(document.getNode(nextNode));
}
if (document.next[nextNode] <= nodeNumber) break;
}
return nl;
}
/* (non-Javadoc)
* @see org.w3c.dom.Element#hasAttribute(java.lang.String)
*/
public boolean hasAttribute(String name) {
return getAttribute(name) != null;
}
/* (non-Javadoc)
* @see org.w3c.dom.Element#hasAttributeNS(java.lang.String, java.lang.String)
*/
public boolean hasAttributeNS(String namespaceURI, String localName) {
return getAttributeNS(namespaceURI, localName) != null;
}
/**
* The method <code>getNamespaceForPrefix</code>
*
* @param name a <code>String</code> value
* @return a <code>String</code> value
*/
public String getNamespaceForPrefix(String name) {
int ns = document.alphaLen[nodeNumber];
if (-1 < ns) {
while (ns < document.nextNamespace
&& document.namespaceParent[ns] == nodeNumber) {
QName nsQName=document.namespaceCode[ns];
if (nsQName.getStringValue().equals("xmlns:" + name))
return nsQName.getNamespaceURI();
++ns;
}
}
return null;
}
/**
* The method <code>getPrefixes</code>
*
* @return a <code>Set</code> value
*/
public Set getPrefixes() {
HashSet set = new HashSet();
int ns = document.alphaLen[nodeNumber];
if (-1 < ns) {
while (ns < document.nextNamespace
&& document.namespaceParent[ns] == nodeNumber) {
QName nsQName=document.namespaceCode[ns];
set.add(nsQName.getStringValue());
++ns;
}
}
return set;
}
/**
* The method <code>declaresNamespacePrefixes</code>
*
* @return a <code>boolean</code> value
*/
public boolean declaresNamespacePrefixes() {
return (document.getNamespacesCountFor(nodeNumber) > 0);
}
/**
* The method <code>getNamespaceMap</code>
*
* @return a <code>Map</code> value
*/
public Map getNamespaceMap() {
Map map = new HashMap();
int ns = document.alphaLen[nodeNumber];
if (-1 < ns) {
while (ns < document.nextNamespace
&& document.namespaceParent[ns] == nodeNumber) {
QName nsQName = document.namespaceCode[ns];
map.put(nsQName.getLocalName(), nsQName.getNamespaceURI());
++ns;
}
}
return map;
}
public int getItemType() {
return Type.ELEMENT;
}
/** ? @see org.w3c.dom.Node#getBaseURI()
*/
public String getBaseURI() {
String baseURI = getAttributeNS(Namespaces.XML_NS, "base");
if ( baseURI == null) {
baseURI = "";
}
int parent = -1;
int test = -1;
test = document.getParentNodeFor(nodeNumber);
if (document.nodeKind[test] != Node.DOCUMENT_NODE) {
parent = test;
}
// fixme! UNDEFINED instead of all the -1s in this file./ljo
while (parent != -1 && document.getNode(parent).getBaseURI() != null) {
if ("".equals(baseURI)) {
baseURI = document.getNode(parent).getBaseURI();
} else {
baseURI = document.getNode(parent).getBaseURI() + "/" + baseURI;
}
test = document.getParentNodeFor(parent);
if (document.nodeKind[test] == Node.DOCUMENT_NODE) {
return baseURI;
} else {
parent = test;
}
}
if ("".equals(baseURI)) {
baseURI = getDocument().getBaseURI();
}
return baseURI;
}
/** ? @see org.w3c.dom.Element#getSchemaTypeInfo()
*/
public TypeInfo getSchemaTypeInfo() {
// maybe TODO - new DOM interfaces - Java 5.0
return null;
}
/** ? @see org.w3c.dom.Element#setIdAttribute(java.lang.String, boolean)
*/
public void setIdAttribute(String name, boolean isId) throws DOMException {
// maybe TODO - new DOM interfaces - Java 5.0
}
/** ? @see org.w3c.dom.Element#setIdAttributeNS(java.lang.String, java.lang.String, boolean)
*/
public void setIdAttributeNS(String namespaceURI, String localName, boolean isId) throws DOMException {
// maybe TODO - new DOM interfaces - Java 5.0
}
/** ? @see org.w3c.dom.Element#setIdAttributeNode(org.w3c.dom.Attr, boolean)
*/
public void setIdAttributeNode(Attr idAttr, boolean isId) throws DOMException {
// maybe TODO - new DOM interfaces - Java 5.0
}
@Override
public void setTextContent( String textContent ) throws DOMException
{
int nodeNr = document.addNode( Node.TEXT_NODE, (short)( document.getTreeLevel( nodeNumber ) + 1 ), null );
document.addChars( nodeNr, textContent.toCharArray(), 0, textContent.length() );
}
public String toString() {
StringBuilder result = new StringBuilder();
result.append("in-memory#");
result.append("element {");
result.append(getQName().getStringValue());
result.append("} {");
NamedNodeMap theAttrs;
if((theAttrs=getAttributes()) != null) {
for(int i = 0; i < theAttrs.getLength(); i++) {
if(i > 0)
result.append(" ");
Node natt=theAttrs.item(i);
if("org.exist.memtree.AttributeImpl".equals(natt.getClass().getName())) {
result.append(((AttributeImpl)natt).toString());
} else {
result.append(((NamespaceNode)natt).toString());
}
}
}
for(int i = 0; i < this.getChildCount(); i++ ) {
if(i > 0)
result.append(" ");
Node child = getChildNodes().item(i);
result.append(child.toString());
}
result.append("} ");
return result.toString();
}
@Override
public String getNodeValue() throws DOMException {
StringBuilder result = new StringBuilder();
for( int i = 0; i < this.getChildCount(); i++ ) {
Node child = getChildNodes().item( i );
if( child instanceof Text ) {
if( i > 0 ) {
result.append( " " );
}
result.append( ( (Text)child ).getData() );
}
}
return( result.toString() );
}
}