////////////////////////////////////////////////////////////////////////////////
// checkstyle: Checks Java source code for adherence to a set of rules.
// Copyright (C) 2001-2003 Oliver Burn
//
// This library 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.1 of the License, or (at your option) any later version.
//
// This library 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 library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
////////////////////////////////////////////////////////////////////////////////
package com.puppycrawl.tools.checkstyle.checks.xpath;
import java.util.ArrayList;
import java.util.Iterator;
import org.jaxen.DefaultNavigator;
import org.jaxen.XPath;
import org.jaxen.util.SingleObjectIterator;
import org.saxpath.SAXPathException;
import com.puppycrawl.tools.checkstyle.api.DetailAST;
import com.puppycrawl.tools.checkstyle.api.TokenTypes;
/**
* Navigates around a DetailAST, using XPath semantics.
* Requires jaxen, http://jaxen.sourceforge.net and
* saxpath, http://sourceforge.net/projects/saxpath/.
* Idea shamelessly stolen from the equivalent PMD code (pmd.sourceforge.net).
* @author Rick Giles
*/
public class DocumentNavigator
extends DefaultNavigator
{
/** Iterator for an empty sequence */
private static final Iterator EMPTY_ITERATOR = new ArrayList().iterator();
/**
* @see org.jaxen.DefaultNavigator#getAttributeName(java.lang.Object)
*/
public String getAttributeName(Object aObject)
{
return ((Attribute) aObject).getName();
}
/**
* @see org.jaxen.DefaultNavigator#getAttributeNamespaceUri
*/
public String getAttributeNamespaceUri(Object aObject)
{
return null;
}
/**
* @see org.jaxen.DefaultNavigator#getAttributeQName(java.lang.Object)
*/
public String getAttributeQName(Object aObject)
{
return ((Attribute) aObject).getName();
}
/**
* @see org.jaxen.DefaultNavigator#getAttributeStringValue(java.lang.Object)
*/
public String getAttributeStringValue(Object aObject)
{
return ((Attribute) aObject).getValue();
}
/**
* @see org.jaxen.DefaultNavigator#getCommentStringValue(java.lang.Object)
*/
public String getCommentStringValue(Object aObject)
{
return null;
}
/**
* @see org.jaxen.DefaultNavigator#getElementName(java.lang.Object)
*/
public String getElementName(Object aObject)
{
final int type = ((DetailAST) aObject).getType();
return TokenTypes.getTokenName(type);
}
/**
* @see org.jaxen.DefaultNavigator#getElementNamespaceUri(java.lang.Object)
*/
public String getElementNamespaceUri(Object aObject)
{
return null;
}
/**
* @see org.jaxen.DefaultNavigator#getElementQName(java.lang.Object)
*/
public String getElementQName(Object aObject)
{
return getElementName(aObject);
}
/**
* @see org.jaxen.DefaultNavigator#getElementStringValue(java.lang.Object)
*/
public String getElementStringValue(Object aObject)
{
return null;
}
/**
* @see org.jaxen.DefaultNavigator#getNamespacePrefix(java.lang.Object)
*/
public String getNamespacePrefix(Object aObject)
{
return null;
}
/**
* @see org.jaxen.DefaultNavigator#getNamespaceStringValue(java.lang.Object)
*/
public String getNamespaceStringValue(Object aObject)
{
return null;
}
/**
* @see org.jaxen.DefaultNavigator#getTextStringValue(java.lang.Object)
*/
public String getTextStringValue(Object aObject)
{
return null;
}
/**
* @see org.jaxen.DefaultNavigator#isAttribute(java.lang.Object)
*/
public boolean isAttribute(Object aObject)
{
return aObject instanceof Attribute;
}
/**
* @see org.jaxen.DefaultNavigator#isComment(java.lang.Object)
*/
public boolean isComment(Object aObject)
{
return false;
}
/**
* @see org.jaxen.DefaultNavigator#isDocument(java.lang.Object)
*/
public boolean isDocument(Object aObject)
{
if (aObject instanceof DetailAST) {
final DetailAST node = (DetailAST) aObject;
return (node.getType() == TokenTypes.EOF);
}
else {
return false;
}
}
/**
* @see org.jaxen.DefaultNavigator#isElement(java.lang.Object)
*/
public boolean isElement(Object aObject)
{
return aObject instanceof DetailAST;
}
/**
* @see org.jaxen.DefaultNavigator#isNamespace(java.lang.Object)
*/
public boolean isNamespace(Object aObject)
{
return false;
}
/**
* @see org.jaxen.DefaultNavigator#isProcessingInstruction(java.lang.Object)
*/
public boolean isProcessingInstruction(Object aObject)
{
return false;
}
/**
* @see org.jaxen.DefaultNavigator#isText(java.lang.Object)
*/
public boolean isText(Object aObject)
{
return false;
}
/**
* @see org.jaxen.DefaultNavigator#parseXPath(java.lang.String)
*/
public XPath parseXPath(String aObject)
throws SAXPathException
{
return null;
}
/**
* @see org.jaxen.Navigator#getParentNode(java.lang.Object)
*/
public Object getParentNode(Object aObject)
{
if (aObject instanceof DetailAST) {
return ((DetailAST) aObject).getParent();
}
else {
return ((Attribute) aObject).getParent();
}
}
/**
* @see org.jaxen.Navigator#getAttributeAxisIterator(java.lang.Object)
*/
public Iterator getAttributeAxisIterator(Object aObject)
{
final DetailAST contextNode = (DetailAST) aObject;
return new AttributeAxisIterator(contextNode);
}
/**
* Get an iterator over all of this node's children.
*
* @param aObject The context node for the child axis.
* @return A possibly-empty iterator (not null).
*/
public Iterator getChildAxisIterator(Object aObject)
{
return new NodeIterator((DetailAST) aObject)
{
/** @see NodeIterator */
protected DetailAST getFirstNode(DetailAST aAST)
{
return getFirstChild(aAST);
}
/** @see NodeIterator */
protected DetailAST getNextNode(DetailAST aAST)
{
return getNextSibling(aAST);
}
};
}
/**
* Get a (single-member) iterator over this node's parent.
*
* @param aObject the context node for the parent axis.
* @return A possibly-empty iterator (not null).
*/
public Iterator getParentAxisIterator(Object aObject)
{
if (isAttribute(aObject)) {
return new SingleObjectIterator(((Attribute) aObject).getParent());
}
else {
DetailAST parent = ((DetailAST) aObject).getParent();
if (parent != null) {
return new SingleObjectIterator(parent);
}
else {
return EMPTY_ITERATOR;
}
}
}
/**
* Get an iterator over all following siblings.
*
* @param aObject the context node for the sibling iterator.
* @return A possibly-empty iterator (not null).
*/
public Iterator getFollowingSiblingAxisIterator(Object aObject)
{
return new NodeIterator((DetailAST) aObject)
{
/** @see NodeIterator */
protected DetailAST getFirstNode(DetailAST aAST)
{
return getNextNode(aAST);
}
/** @see NodeIterator */
protected DetailAST getNextNode(DetailAST aAST)
{
return getNextSibling(aAST);
}
};
}
/**
* Get an iterator over all preceding siblings.
*
* @param aObject The context node for the preceding sibling axis.
* @return A possibly-empty iterator (not null).
*/
public Iterator getPrecedingSiblingAxisIterator(Object aObject)
{
return new NodeIterator((DetailAST) aObject)
{
/** @see NodeIterator */
protected DetailAST getFirstNode(DetailAST aAST)
{
return getNextNode(aAST);
}
/** @see NodeIterator */
protected DetailAST getNextNode(DetailAST aAST)
{
return getPreviousSibling(aAST);
}
};
}
/**
* Get an iterator over all following nodes, depth-first.
*
* @param aObject The context node for the following axis.
* @return A possibly-empty iterator (not null).
*/
public Iterator getFollowingAxisIterator(Object aObject)
{
return new NodeIterator((DetailAST) aObject)
{
/** @see NodeIterator */
protected DetailAST getFirstNode(DetailAST aAST)
{
if (aAST == null) {
return null;
}
else {
final DetailAST sibling = getNextSibling(aAST);
if (sibling == null) {
return getFirstNode(aAST.getParent());
}
else {
return sibling;
}
}
}
/** @see NodeIterator */
protected DetailAST getNextNode(DetailAST aAST)
{
if (aAST == null) {
return null;
}
else {
DetailAST n = getFirstChild(aAST);
if (n == null) {
n = getNextSibling(aAST);
}
if (n == null) {
return getFirstNode(aAST.getParent());
}
else {
return n;
}
}
}
};
}
/**
* Get an iterator over all preceding nodes, depth-first.
*
* @param aObject The context node for the preceding axis.
* @return A possibly-empty iterator (not null).
*/
public Iterator getPrecedingAxisIterator(Object aObject)
{
return new NodeIterator((DetailAST) aObject)
{
/** @see NodeIterator */
protected DetailAST getFirstNode(DetailAST aAST)
{
if (aAST == null) {
return null;
}
else {
final DetailAST sibling = getPreviousSibling(aAST);
if (sibling == null) {
return getFirstNode(aAST.getParent());
}
else {
return sibling;
}
}
}
/** @see NodeIterator */
protected DetailAST getNextNode(DetailAST aAST)
{
if (aAST == null) {
return null;
}
else {
DetailAST n = getLastChild(aAST);
if (n == null) {
n = getPreviousSibling(aAST);
}
if (n == null) {
return getFirstNode(aAST.getParent());
}
else {
return n;
}
}
}
};
}
/** @see org.jaxen.Navigator#getDocumentNode(java.lang.Object) */
public Object getDocumentNode(Object aObject)
{
if (isDocument(aObject)) {
return aObject;
}
else {
return getDocumentNode(getParentNode(aObject));
}
}
}