/*
* $Header$
* $Revision: 1156 $
* $Date: 2006-06-03 13:04:05 -0700 (Sat, 03 Jun 2006) $
*
* ====================================================================
*
* Copyright 2000-2003 bob mcwhirter & James Strachan.
* All rights reserved.
*
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * 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.
*
* * Neither the name of the Jaxen Project nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS 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 COPYRIGHT OWNER
* OR 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 Jaxen Project and was originally
* created by bob mcwhirter <bob@werken.com> and
* James Strachan <jstrachan@apache.org>. For more information on the
* Jaxen Project, please see <http://www.jaxen.org/>.
*
* $Id: DocumentNavigator.java 1156 2006-06-03 20:04:05Z elharo $
*/
package org.jaxen.xom;
import nu.xom.Attribute;
import nu.xom.Comment;
import nu.xom.Document;
import nu.xom.Element;
import nu.xom.ProcessingInstruction;
import nu.xom.Text;
import nu.xom.Node;
import nu.xom.Builder;
import nu.xom.NodeFactory;
import nu.xom.ParentNode;
import org.jaxen.XPath;
import org.jaxen.UnsupportedAxisException;
import org.jaxen.FunctionCallException;
import org.jaxen.BaseXPath;
import org.jaxen.JaxenConstants;
import org.jaxen.util.SingleObjectIterator;
import org.jaxen.saxpath.SAXPathException;
import java.util.Iterator;
import java.util.HashMap;
import java.util.Map;
/**
* Interface for navigating around the XOM object model.
*
* <p>
* This class is not intended for direct usage, but is
* used by the Jaxen engine during evaluation.
* </p>
*
* @see XPath
*
*/
public class DocumentNavigator extends org.jaxen.DefaultNavigator
{
/**
*
*/
private static final long serialVersionUID = 3159311338575942877L;
public boolean isAttribute(Object o) {
return o instanceof Attribute;
}
public boolean isComment(Object o) {
return o instanceof Comment;
}
public boolean isDocument(Object o) {
return o instanceof Document;
}
public boolean isElement(Object o) {
return o instanceof Element;
}
public boolean isNamespace(Object o) {
return o instanceof XPathNamespace;
}
public boolean isProcessingInstruction(Object o) {
return o instanceof ProcessingInstruction;
}
public boolean isText(Object o) {
return o instanceof Text;
}
//
public String getAttributeName(Object o) {
return (isAttribute(o) ? ((Attribute)o).getLocalName() : null);
}
public String getAttributeNamespaceUri(Object o) {
return (isAttribute(o) ? ((Attribute)o).getNamespaceURI() : null);
}
public String getAttributeQName(Object o) {
return (isAttribute(o) ? ((Attribute)o).getQualifiedName() : null);
}
public String getAttributeStringValue(Object o) {
return (isAttribute(o) ? ((Attribute)o).getValue() : null);
}
//
public String getCommentStringValue(Object o) {
return (isComment(o) ? ((Comment)o).getValue() : null);
}
public String getElementName(Object o) {
return (isElement(o) ? ((Element)o).getLocalName() : null);
}
public String getElementNamespaceUri(Object o) {
return (isElement(o) ? ((Element)o).getNamespaceURI() : null);
}
public String getElementQName(Object o) {
return (isElement(o) ? ((Element)o).getQualifiedName() : null);
}
public String getElementStringValue(Object o) {
return (o instanceof Node ? ((Node)o).getValue() : null);
}
//
public String getNamespacePrefix(Object o) {
if (isElement(o)) {
return ((Element)o).getNamespacePrefix();
} else if (isAttribute(o)) {
return ((Attribute)o).getNamespacePrefix();
} else if (o instanceof XPathNamespace) {
return ((XPathNamespace)o).getNamespacePrefix();
}
return null;
}
public String getNamespaceStringValue(Object o) {
if (isElement(o)) {
return ((Element)o).getNamespaceURI();
} else if (isAttribute(o)) {
return ((Attribute)o).getNamespaceURI();
} else if (o instanceof XPathNamespace) {
return ((XPathNamespace)o).getNamespaceURI();
}
return null;
}
//
public String getTextStringValue(Object o) {
return (o instanceof Text ? ((Text)o).getValue() : null);
}
//
public Object getDocument(String s) throws FunctionCallException {
try {
return new Builder(new NodeFactory()).build(s);
} catch (Exception pe) {
throw new FunctionCallException(pe);
}
}
public Object getDocumentNode(Object o) {
ParentNode parent = null;
if (o instanceof ParentNode) {
parent = (ParentNode)o;
} else if (o instanceof Node) {
parent = ((Node)o).getParent();
}
return parent.getDocument();
}
//
private abstract static class IndexIterator implements Iterator {
private Object o = null;
private int pos = 0, end = -1;
public IndexIterator(Object o, int pos, int end) {
this.o = o;
this.pos = pos;
this.end = end;
}
public boolean hasNext() {
return pos < end;
}
public abstract Object get(Object o, int i);
public Object next() {
return get(o, pos++);
}
public void remove() {
throw new UnsupportedOperationException();
}
}
//
public Iterator getAttributeAxisIterator(Object o) {
if (isElement(o)) {
return new IndexIterator(o, 0, ((Element)o).getAttributeCount()) {
public Object get(Object o, int i) {
return ((Element)o).getAttribute(i);
}
};
}
return JaxenConstants.EMPTY_ITERATOR;
}
public Iterator getChildAxisIterator(Object o) {
if (isElement(o) || (o instanceof Document)) {
return new IndexIterator(o, 0, ((ParentNode)o).getChildCount()) {
public Object get(Object o, int i) {
return ((ParentNode)o).getChild(i);
}
};
}
return JaxenConstants.EMPTY_ITERATOR;
}
//
public Iterator getParentAxisIterator(Object o) {
Object parent = null;
if (o instanceof Node) {
parent = ((Node)o).getParent();
} else if (isNamespace(o)) {
parent = ((XPathNamespace)o).getElement();
}
return (parent != null ? new SingleObjectIterator(parent) : null);
}
public Object getParentNode(Object o) {
return (o instanceof Node ? ((Node)o).getParent() : null);
}
//
public Iterator getPrecedingAxisIterator(Object o) throws UnsupportedAxisException {
return super.getPrecedingAxisIterator(o);
}
public Iterator getPrecedingSiblingAxisIterator(Object o) throws UnsupportedAxisException {
return super.getPrecedingSiblingAxisIterator(o);
}
//
public String getProcessingInstructionData(Object o) {
return (o instanceof ProcessingInstruction ? ((ProcessingInstruction)o).getValue() : null);
}
public String getProcessingInstructionTarget(Object o) {
return (o instanceof ProcessingInstruction ? ((ProcessingInstruction)o).getTarget() : null);
}
//
public String translateNamespacePrefixToUri(String s, Object o) {
Element element = null;
if (o instanceof Element) {
element = (Element) o;
} else if (o instanceof ParentNode) {
}
else if (o instanceof Node) {
element = (Element)((Node)o).getParent();
}
else if (o instanceof XPathNamespace)
{
element = ((XPathNamespace)o).getElement();
}
if (element != null) {
return element.getNamespaceURI(s);
}
return null;
}
//
public XPath parseXPath(String s) throws SAXPathException {
return new BaseXPath(s, this);
}
//
/** Wrapper for XOM namespace nodes to give them a parent,
* as required by the XPath data model.
*
* @author Erwin Bolwidt
*/
private static class XPathNamespace
{
private Element element;
private String uri, prefix;
public XPathNamespace(Element elt, String uri, String prefix)
{
element = elt;
this.uri = uri;
this.prefix = prefix;
}
/** Returns the XOM element from which this namespace node has been
* retrieved. The result may be null when the namespace node has not yet
* been assigned to an element.
*/
public Element getElement()
{
return element;
}
public String getNamespaceURI()
{
return uri;
}
public String getNamespacePrefix()
{
return prefix;
}
public String toString()
{
return ( "[xmlns:" + prefix + "=\"" +
uri + "\", element=" +
element.getLocalName() + "]" );
}
}
//
private boolean addNamespaceForElement(Element elt, String uri, String prefix, Map map)
{
if (uri != null && uri.length() > 0 && (! map.containsKey(prefix))) {
map.put(prefix, new XPathNamespace(elt, uri, prefix));
return true;
}
return false;
}
public Iterator getNamespaceAxisIterator(Object o)
{
if (! isElement(o)) {
return JaxenConstants.EMPTY_ITERATOR;
}
Map nsMap = new HashMap();
Element elt = (Element)o;
ParentNode parent = elt;
while (parent instanceof Element) {
elt = (Element)parent;
String uri = elt.getNamespaceURI();
String prefix = elt.getNamespacePrefix();
addNamespaceForElement(elt, uri, prefix, nsMap);
int count = elt.getNamespaceDeclarationCount();
for (int i = 0; i < count; i++) {
prefix = elt.getNamespacePrefix(i);
uri = elt.getNamespaceURI(prefix);
addNamespaceForElement(elt, uri, prefix, nsMap);
}
parent = elt.getParent();
}
addNamespaceForElement(elt, "http://www.w3.org/XML/1998/namespace", "xml", nsMap);
return nsMap.values().iterator();
}
}