package gnu.xml.xpath;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.Set;
import org.w3c.dom.Attr;
import org.w3c.dom.Node;
public final class Steps
extends Path
{
final LinkedList path;
public Steps()
{
this(new LinkedList());
}
Steps(LinkedList path)
{
this.path = path;
}
public boolean matches(Node context)
{
return matches(context, path.size() - 1);
}
boolean matches(Node context, int pos)
{
Pattern right = (Pattern) path.get(pos);
if (!right.matches(context))
{
return false;
}
if (pos > 0)
{
Pattern left = (Pattern) path.get(pos - 1);
Iterator j = possibleContexts(right, context).iterator();
while (j.hasNext())
{
Node candidate = (Node) j.next();
if (left.matches(candidate) &&
matches(candidate, pos - 1))
{
return true;
}
}
return false;
}
return true;
}
Collection possibleContexts(Pattern pattern, Node context)
{
if (pattern instanceof Selector)
{
Selector s = (Selector) pattern;
Collection candidates = new LinkedHashSet();
switch (s.axis)
{
case Selector.PARENT:
s.addChildNodes(context, candidates, false);
break;
case Selector.ANCESTOR:
s.addChildNodes(context, candidates, true);
break;
case Selector.ANCESTOR_OR_SELF:
candidates.add (context);
s.addChildNodes(context, candidates, true);
break;
case Selector.CHILD:
s.addParentNode(context, candidates, false);
break;
case Selector.DESCENDANT:
s.addParentNode(context, candidates, true);
break;
case Selector.DESCENDANT_OR_SELF:
candidates.add(context);
s.addParentNode(context, candidates, true);
break;
case Selector.PRECEDING_SIBLING:
s.addFollowingNodes(context, candidates, false);
break;
case Selector.FOLLOWING_SIBLING:
s.addPrecedingNodes(context, candidates, false);
break;
case Selector.PRECEDING:
s.addFollowingNodes(context, candidates, true);
break;
case Selector.FOLLOWING:
s.addPrecedingNodes(context, candidates, true);
break;
case Selector.ATTRIBUTE:
case Selector.NAMESPACE:
if (context.getNodeType() == Node.ATTRIBUTE_NODE)
{
candidates.add(((Attr) context).getOwnerElement());
}
break;
case Selector.SELF:
candidates.add(context);
break;
}
return candidates;
}
return Collections.EMPTY_SET;
}
public Object evaluate(Node context, int pos, int len)
{
Iterator i = path.iterator();
Expr lhs = (Expr) i.next();
Object val = lhs.evaluate(context, pos, len);
while (val instanceof Collection && i.hasNext())
{
Path rhs = (Path) i.next();
val = rhs.evaluate(context, (Collection) val);
}
return val;
}
Collection evaluate(Node context, Collection ns)
{
Iterator i = path.iterator();
Expr lhs = (Expr) i.next();
if (lhs instanceof Path)
{
ns = ((Path) lhs).evaluate(context, ns);
}
else
{
Set acc = new LinkedHashSet();
int pos = 1, len = ns.size();
for (Iterator j = ns.iterator(); j.hasNext(); )
{
Node node = (Node) j.next();
Object ret = lhs.evaluate(node, pos++, len);
if (ret instanceof Collection)
{
acc.addAll((Collection) ret);
}
}
ns = acc;
}
while (i.hasNext())
{
Path rhs = (Path) i.next();
ns = rhs.evaluate(context, ns);
}
return ns;
}
public Expr clone(Object context)
{
int len = path.size();
LinkedList path2 = new LinkedList();
for (int i = 0; i < len; i++)
{
path2.add(((Expr) path.get(i)).clone(context));
}
return new Steps(path2);
}
public String toString()
{
StringBuffer buf = new StringBuffer();
Iterator i = path.iterator();
Expr expr = (Expr) i.next();
if (!(expr instanceof Root))
{
buf.append(expr);
}
while (i.hasNext())
{
expr = (Expr) i.next();
buf.append('/');
buf.append(expr);
}
return buf.toString();
}
}