/*
* $Id: AnyNode.java,v 1.21 2002/09/16 08:05:03 jkl Exp $
*
* Copyright (c) 2002 Njet Communications Ltd. All Rights Reserved.
*
* Use is subject to license terms, as defined in
* Anvil Sofware License, Version 1.1. See LICENSE
* file, or http://njet.org/license-1.1.txt
*/
package anvil.core.xml;
import anvil.core.Any;
import anvil.core.AnyAbstractClass;
import anvil.core.AnyList;
import anvil.core.Array;
import anvil.script.Context;
import anvil.java.util.BindingEnumeration;
import anvil.util.Conversions;
import java.util.ArrayList;
import java.io.IOException;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.DocumentType;
import org.w3c.dom.DOMException;
import org.w3c.dom.Element;
import org.w3c.dom.Entity;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.Notation;
import org.w3c.dom.ProcessingInstruction;
///
/// @class Node.
/// Node in XML tree.
///
/// @operator "sizeof Node"
/// Returns the number of childs nodes of this node.
///
/// @operator "list Node.elementName"
/// Returns list of elements (tags) whose name equals to given 'elementName'.
/// If no elements could be found, empty list is returned.
///
/// @operator "list Node[string elementName]"
/// Returns list of elements (tags) whose name equals to given 'elementName'.
/// If no elements could be found, empty list is returned.
///
/// @operator "Node Node[int index]"
/// Returns child node at 'index', or <code>null</code> if 'index'
/// was out of range.
///
/// @operator "enumeration *Node"
/// Returns the enumeration of child nodes of this node.
///
/**
* class AnyNode.
*
* @author: Jani Lehtim�ki
*/
public class AnyNode extends AnyAbstractClass
{
public static final Any TYPE_TEXT = Any.create("Text");
public static final Any TYPE_CDATA_SECTION = Any.create("CDATASection");
public static final Any TYPE_COMMENT = Any.create("Comment");
public static final Any TYPE_ATTRIBUTE = Any.create("Attr");
public static final Any TYPE_ELEMENT = Any.create("Element");
public static final Any TYPE_DOCUMENT_TYPE = Any.create("DocumentType");
public static final Any TYPE_ENTITY = Any.create("Entity");
public static final Any TYPE_ENTITY_REFERENCE = Any.create("EntityReference");
public static final Any TYPE_NOTATION = Any.create("Notation");
public static final Any TYPE_PROCESSING_INSTRUCTION = Any.create("ProcessingInstruction");
public static final Any TYPE_DOCUMENT_FRAGMENT = Any.create("DocumentFragment");
public static final Any TYPE_DOCUMENT = Any.create("Document");
private Node _node;
private int _type;
public AnyNode(Node node)
{
_node = node;
_type = node.getNodeType();
}
public final anvil.script.ClassType classOf()
{
return __class__;
}
public Object clone()
{
return new AnyNode(_node.cloneNode(false));
}
public Any copy()
{
return new AnyNode(_node.cloneNode(true));
}
public int sizeOf()
{
NodeList nodeList = _node.getChildNodes();
if (nodeList != null) {
return nodeList.getLength();
} else {
return 0;
}
}
public Object toObject()
{
return _node;
}
public String toString()
{
switch(_type) {
case Node.ELEMENT_NODE:
StringBuffer tag = new StringBuffer();
tag.append('<');
tag.append(((Element)_node).getTagName());
NamedNodeMap list = _node.getAttributes();
if (list != null) {
int length = list.getLength();
for(int i=0; i<length; i++) {
Attr attr = (Attr)list.item(i);
tag.append(' ');
tag.append(attr.getName());
String value = attr.getValue();
if (value != null) {
tag.append('=');
tag.append('"');
tag.append(anvil.util.Conversions.encodeEntities(value));
tag.append('"');
}
}
}
if (!_node.hasChildNodes()) {
tag.append(' ');
tag.append('/');
}
tag.append('>');
return tag.toString();
case Node.COMMENT_NODE:
return "<!--" + _node.getNodeValue() + "-->";
default:
String value = _node.getNodeValue();
return (value != null) ? value : "";
}
}
public Any getAttribute(Context context, String attribute)
{
NodeList nodeList = _node.getChildNodes();
if (nodeList != null) {
int length = nodeList.getLength();
ArrayList vector = null;
for(int i=0; i<length; i++) {
Node child = nodeList.item(i);
if (child.getNodeType() == Node.ELEMENT_NODE) {
if (((Element)child).getTagName().equalsIgnoreCase(attribute)) {
if (vector == null) {
vector = new ArrayList();
}
vector.add(new AnyNode(child));
}
}
}
if (vector != null) {
return new AnyList((Any[])vector.toArray(
new Any[vector.size()]));
}
}
return EMPTY_TUPLE;
}
public Any setAttribute(Context context, String attribute, Any value)
{
return value;
}
public Any checkAttribute(Context context, String attribute)
{
return getAttribute(context, attribute);
}
public boolean deleteAttribute(Context context, String attribute)
{
return false;
}
public Any getReference(Context context, Any index)
{
if (index.isInt()) {
NodeList nodeList = _node.getChildNodes();
if (nodeList != null) {
Node child = nodeList.item(index.toInt());
if (child != null) {
return new AnyNode(child);
}
}
} else {
return getAttribute(context, index.toString());
}
return NULL;
}
public Any setReference(Context context, Any index, Any value)
{
return value;
}
public Any setReference(Context context, Any value)
{
return this;
}
public Any checkReference(Context context, Any index)
{
return getReference(context, index);
}
public boolean deleteReference(Context context, Any index)
{
return false;
}
public BindingEnumeration enumeration()
{
return new NodeListEnumeration(_node.getChildNodes());
}
/// @method getNodeType
/// Returns the type of this node.
/// @synopsis int getNodeType()
/// @return the type of node as an integer constant
public Any m_getNodeType()
{
return Any.create(_type);
}
/// @method getNodeTypeName
/// Returns the type of this node as string, which is one of
/// <ul>
/// <li>"Text"
/// <li>"CDATASection"
/// <li>"Comment"
/// <li>"Attr"
/// <li>"Element"
/// <li>"DocumentType"
/// <li>"Entity"
/// <li>"EntityReference"
/// <li>"Notation"
/// <li>"ProcessingInstruction"
/// <li>"DocumentFragment"
/// <li>"Document"
/// </ul>
/// @synopsis string getNodeTypeName()
/// @return type of node
public Any m_getNodeTypeName()
{
switch(_type) {
case Node.TEXT_NODE: return TYPE_TEXT;
case Node.CDATA_SECTION_NODE: return TYPE_CDATA_SECTION;
case Node.COMMENT_NODE: return TYPE_COMMENT;
case Node.ATTRIBUTE_NODE: return TYPE_ATTRIBUTE;
case Node.ELEMENT_NODE: return TYPE_ELEMENT;
case Node.DOCUMENT_TYPE_NODE: return TYPE_DOCUMENT_TYPE;
case Node.ENTITY_NODE: return TYPE_ENTITY;
case Node.ENTITY_REFERENCE_NODE: return TYPE_ENTITY_REFERENCE;
case Node.NOTATION_NODE: return TYPE_NOTATION;
case Node.PROCESSING_INSTRUCTION_NODE: return TYPE_PROCESSING_INSTRUCTION;
case Node.DOCUMENT_FRAGMENT_NODE: return TYPE_DOCUMENT_FRAGMENT;
case Node.DOCUMENT_NODE: return TYPE_DOCUMENT;
default: return EMPTY_STRING;
}
}
/// @method getNodeName
/// Returns the name of this node.
/// @synopsis string getNodeName()
/// @return the name of node
public Any m_getNodeName()
{
return Any.create(_node.getNodeName());
}
/// @method getNodeValue
/// Returns the value of this node.
/// @synopsis string getNodeValue()
/// @return the value of node
public Any m_getNodeValue(Context context)
{
try {
return Any.create(_node.getNodeValue());
} catch (DOMException e) {
throw context.XMLError(e.getMessage(), null);
}
}
/// @method getOwnerDocument
/// Returns the owner document of this node.
/// @synopsis Node getOwnerDocument()
/// @return the document where this node belongs to,
/// returns <code>null</code> is this node is already document node.
public Any m_getOwnerDocument()
{
Node document = _node.getOwnerDocument();
return (document != null) ? new AnyNode(document) : NULL;
}
/// @method getParentNode
/// Returns the parent node of this node.
/// @synopsis Node getParentNode()
/// @return the parent node of this node, returns <code>null</code>
/// if this node does not have a parent.
public Any m_getParentNode()
{
Node parent = _node.getParentNode();
return (parent != null) ? new AnyNode(parent) : NULL;
}
/// @method getNextSibling
/// Returns the next sibling of this node.
/// @synopsis Node getNextSibling()
/// @return next sibling or <code>null</code> if there is no such node.
/// Next sibling is child of this node's parent that is immediately
/// next to this node.
public Any m_getNextSibling()
{
Node sibling = _node.getNextSibling();
return (sibling != null) ? new AnyNode(sibling) : NULL;
}
/// @method getPreviousSibling
/// Returns the previous sibling of this node.
/// @synopsis Node getPreviousSibling()
/// @return next sibling or <code>null</code> if there is no such node.
/// Previous sibling is child of this node's parent that is immediately
/// next to this node.
public Any m_getPreviousSibling()
{
Node sibling = _node.getPreviousSibling();
return (sibling != null) ? new AnyNode(sibling) : NULL;
}
/// @method hasAttributes
/// Checks if this node has attributes.
/// @synopsis boolean hasAttributes()
/// @return <code>true</code> if node has attributes
public Any m_hasAttributes()
{
return _node.hasAttributes() ? TRUE : FALSE;
}
/// @method getAttributes
/// Returns the attributes of this node.
/// @synopsis array getAttributes()
/// @return array of attributes for this node. Attributes are mapped
/// into array with their respective names.
public Any m_getAttributes()
{
if (_type == Node.ELEMENT_NODE) {
NamedNodeMap map = _node.getAttributes();
int length = map.getLength();
Array attributes = new Array(length);
for(int i=0; i<length; i++) {
Attr attr = (Attr)map.item(i);
attributes.append(attr.getName(), Any.create(attr.getValue()));
}
return attributes;
} else {
return NULL;
}
}
/// @method getAttribute
/// Returns the given attribute from this node.
/// @synopsis string getAttribute(string name)
/// @return The value of attribute, null if node is not an element,
/// empty string if attribute does not exist, or does not have any
/// value - specified or default.
public static final Object[] p_getAttribute = { "name" };
public Any m_getAttribute(String name)
{
if (_type == Node.ELEMENT_NODE) {
return Any.create(((Element)_node).getAttribute(name));
} else {
return NULL;
}
}
/// @method hasChildNodes
/// Checks if this node has children.
/// @synopsis boolean hasChildNodes()
/// @return <code>true</code> if node has children
public Any m_hasChildNodes()
{
return _node.hasChildNodes() ? TRUE : FALSE;
}
/// @method getChildNodes
/// Returns list of child nodes of this node.
/// @synopsis list getChildNodes()
/// @return array of children for this node. Returns empty list if
/// node does not have any children.
public Any m_getChildNodes()
{
if (_node.hasChildNodes()) {
NodeList nodelist = _node.getChildNodes();
int length = nodelist.getLength();
Any[] list = new Any[length];
for(int i=0; i<length; i++) {
list[i] = new AnyNode(nodelist.item(i));
}
return new AnyList(list);
} else {
return EMPTY_TUPLE;
}
}
/// @method getRootNode
/// Gets the root element.
/// @synopsis Node getRootNode()
/// @return the root node of document where this node belongs to
public Any m_getRootNode()
{
Node root = null;
if (_type == Node.DOCUMENT_NODE) {
root = ((Document)_node).getDocumentElement();
} else {
Document doc = _node.getOwnerDocument();
if (doc != null) {
root = doc.getDocumentElement();
}
}
return (root != null) ? new AnyNode(root) : NULL;
}
/// @method getDocumentType
/// Return the document type of document to which this node belongs to.
/// @synopsis Node getDocumentType()
/// @return document type of <i>document</i> node
public Any m_getDocumentType()
{
if (_type == Node.DOCUMENT_NODE) {
DocumentType docType = ((Document)_node).getDoctype();
if (docType != null) {
return new AnyNode(docType);
}
}
return NULL;
}
/// @method getEntities
/// Return the array of entities from document type node.
/// @synopsis array getEntities()
/// @return array of entities of <i>document type</i> node
public Any m_getEntities()
{
if (_type == Node.DOCUMENT_TYPE_NODE) {
NamedNodeMap map = ((DocumentType)_node).getEntities();
int length = map.getLength();
Array entities = new Array(length);
for(int i=0; i<length; i++) {
Node entity = map.item(i);
if (entity.getNodeType() == Node.DOCUMENT_TYPE_NODE) {
entities.append(((DocumentType)entity).getName(), new AnyNode(entity));
}
}
return entities;
} else {
return NULL;
}
}
/// @method getNotations
/// Return the array of notations from document type node.
/// @synopsis array getNotations()
/// @return array of notations of <i>document type</i> node
public Any m_getNotations()
{
if (_type == Node.DOCUMENT_TYPE_NODE) {
NamedNodeMap map = ((DocumentType)_node).getNotations();
int length = map.getLength();
Array notations = new Array(length);
for(int i=0; i<length; i++) {
Node entity = map.item(i);
if (entity.getNodeType() == Node.DOCUMENT_TYPE_NODE) {
notations.append(((DocumentType)entity).getName(), new AnyNode(entity));
}
}
return notations;
} else {
return NULL;
}
}
/// @method getPublicId
/// Returns the public id of this node.
/// @synopsis string getPublicId()
/// @return public id of <i>document type</i>, <i>entity</i>
/// and <i>notation</i> nodes
public Any m_getPublicId()
{
switch(_type) {
case Node.DOCUMENT_TYPE_NODE:
return Any.create(((DocumentType)_node).getPublicId());
case Node.ENTITY_NODE:
return Any.create(((Entity)_node).getPublicId());
case Node.NOTATION_NODE:
return Any.create(((Notation)_node).getPublicId());
default:
return NULL;
}
}
/// @method getSystemId
/// Returns the system id of this node.
/// @synopsis string getSystemId()
/// @return system id of <i>document type</i>, <i>entity</i>
/// and <i>notation</i> nodes
public Any m_getSystemId()
{
switch(_type) {
case Node.DOCUMENT_TYPE_NODE:
return Any.create(((DocumentType)_node).getSystemId());
case Node.ENTITY_NODE:
return Any.create(((Entity)_node).getSystemId());
case Node.NOTATION_NODE:
return Any.create(((Notation)_node).getSystemId());
default:
return NULL;
}
}
/// @method getTarget
/// Returns the target of instruction node.
/// @synopsis string getTarget()
/// @return target of <i>instruction</i> node
public Any m_getTarget()
{
if (_type == Node.PROCESSING_INSTRUCTION_NODE) {
return Any.create(((ProcessingInstruction)_node).getTarget());
} else {
return NULL;
}
}
/// @method getData
/// Returns the data of instruction node.
/// @synopsis string getData()
/// @return data of <i>instruction</i> node
public Any m_getData()
{
if (_type == Node.PROCESSING_INSTRUCTION_NODE) {
return Any.create(((ProcessingInstruction)_node).getData());
} else {
return NULL;
}
}
public class NodeListEnumeration implements BindingEnumeration {
private NodeList _nodeList;
private int _index;
public NodeListEnumeration(NodeList nodeList)
{
_nodeList = nodeList;
}
public boolean hasMoreElements()
{
return _index < _nodeList.getLength();
}
public Object nextKey()
{
return Any.create(_index);
}
public Object nextElement()
{
if (_index < _nodeList.getLength()) {
return new AnyNode(_nodeList.item(_index++));
} else {
return null;
}
}
}
public static final anvil.script.compiler.NativeClass __class__ =
new anvil.script.compiler.NativeClass("Node", AnyNode.class,
//DOC{{
""+
"\n" +
" @class Node.\n" +
" Node in XML tree.\n" +
"\n" +
" @operator \"sizeof Node\"\n" +
" Returns the number of childs nodes of this node.\n" +
"\n" +
" @operator \"list Node.elementName\"\n" +
" Returns list of elements (tags) whose name equals to given 'elementName'.\n" +
" If no elements could be found, empty list is returned.\n" +
"\n" +
" @operator \"list Node[string elementName]\"\n" +
" Returns list of elements (tags) whose name equals to given 'elementName'.\n" +
" If no elements could be found, empty list is returned.\n" +
"\n" +
" @operator \"Node Node[int index]\"\n" +
" Returns child node at 'index', or <code>null</code> if 'index'\n" +
" was out of range.\n" +
"\n" +
" @operator \"enumeration *Node\"\n" +
" Returns the enumeration of child nodes of this node.\n" +
"\n" +
" @method getNodeType\n" +
" Returns the type of this node.\n" +
" @synopsis int getNodeType()\n" +
" @return the type of node as an integer constant\n" +
" @method getNodeTypeName\n" +
" Returns the type of this node as string, which is one of\n" +
" <ul>\n" +
" <li>\"Text\" \n" +
" <li>\"CDATASection\"\n" +
" <li>\"Comment\"\n" +
" <li>\"Attr\"\n" +
" <li>\"Element\"\n" +
" <li>\"DocumentType\" \n" +
" <li>\"Entity\" \n" +
" <li>\"EntityReference\" \n" +
" <li>\"Notation\"\n" +
" <li>\"ProcessingInstruction\" \n" +
" <li>\"DocumentFragment\" \n" +
" <li>\"Document\"\n" +
" </ul> \n" +
" @synopsis string getNodeTypeName()\n" +
" @return type of node\n" +
" @method getNodeName\n" +
" Returns the name of this node.\n" +
" @synopsis string getNodeName()\n" +
" @return the name of node\n" +
" @method getNodeValue\n" +
" Returns the value of this node.\n" +
" @synopsis string getNodeValue()\n" +
" @return the value of node\n" +
" @method getOwnerDocument\n" +
" Returns the owner document of this node.\n" +
" @synopsis Node getOwnerDocument()\n" +
" @return the document where this node belongs to,\n" +
" returns <code>null</code> is this node is already document node.\n" +
" @method getParentNode\n" +
" Returns the parent node of this node.\n" +
" @synopsis Node getParentNode()\n" +
" @return the parent node of this node, returns <code>null</code>\n" +
" if this node does not have a parent.\n" +
" @method getNextSibling\n" +
" Returns the next sibling of this node.\n" +
" @synopsis Node getNextSibling()\n" +
" @return next sibling or <code>null</code> if there is no such node.\n" +
" Next sibling is child of this node's parent that is immediately\n" +
" next to this node.\n" +
" @method getPreviousSibling\n" +
" Returns the previous sibling of this node.\n" +
" @synopsis Node getPreviousSibling()\n" +
" @return next sibling or <code>null</code> if there is no such node.\n" +
" Previous sibling is child of this node's parent that is immediately\n" +
" next to this node.\n" +
" @method hasAttributes\n" +
" Checks if this node has attributes.\n" +
" @synopsis boolean hasAttributes()\n" +
" @return <code>true</code> if node has attributes\n" +
" @method getAttributes\n" +
" Returns the attributes of this node.\n" +
" @synopsis array getAttributes()\n" +
" @return array of attributes for this node. Attributes are mapped\n" +
" into array with their respective names.\n" +
" @method getAttribute\n" +
" Returns the given attribute from this node.\n" +
" @synopsis string getAttribute(string name)\n" +
" @return The value of attribute, null if node is not an element,\n" +
" empty string if attribute does not exist, or does not have any \n" +
" value - specified or default.\n" +
" @method hasChildNodes\n" +
" Checks if this node has children.\n" +
" @synopsis boolean hasChildNodes()\n" +
" @return <code>true</code> if node has children\n" +
" @method getChildNodes\n" +
" Returns list of child nodes of this node.\n" +
" @synopsis list getChildNodes()\n" +
" @return array of children for this node. Returns empty list if\n" +
" node does not have any children.\n" +
" @method getRootNode\n" +
" Gets the root element.\n" +
" @synopsis Node getRootNode()\n" +
" @return the root node of document where this node belongs to\n" +
" @method getDocumentType\n" +
" Return the document type of document to which this node belongs to.\n" +
" @synopsis Node getDocumentType()\n" +
" @return document type of <i>document</i> node\n" +
" @method getEntities\n" +
" Return the array of entities from document type node.\n" +
" @synopsis array getEntities()\n" +
" @return array of entities of <i>document type</i> node\n" +
" @method getNotations\n" +
" Return the array of notations from document type node.\n" +
" @synopsis array getNotations()\n" +
" @return array of notations of <i>document type</i> node\n" +
" @method getPublicId\n" +
" Returns the public id of this node.\n" +
" @synopsis string getPublicId()\n" +
" @return public id of <i>document type</i>, <i>entity</i>\n" +
" and <i>notation</i> nodes\n" +
" @method getSystemId\n" +
" Returns the system id of this node.\n" +
" @synopsis string getSystemId()\n" +
" @return system id of <i>document type</i>, <i>entity</i>\n" +
" and <i>notation</i> nodes\n" +
" @method getTarget\n" +
" Returns the target of instruction node.\n" +
" @synopsis string getTarget()\n" +
" @return target of <i>instruction</i> node\n" +
" @method getData\n" +
" Returns the data of instruction node.\n" +
" @synopsis string getData()\n" +
" @return data of <i>instruction</i> node\n"
//}}DOC
);
static {
XMLModule.class.getName();
}
}