package gnu.xml.transform;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import javax.xml.namespace.QName;
import javax.xml.xpath.XPathFunction;
import javax.xml.xpath.XPathFunctionException;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import gnu.xml.xpath.Expr;
import gnu.xml.xpath.Function;
import gnu.xml.xpath.Pattern;
final class KeyFunction
extends Pattern
implements XPathFunction, Function
{
final Stylesheet stylesheet;
List args;
KeyFunction(Stylesheet stylesheet)
{
this.stylesheet = stylesheet;
}
public Object evaluate(List args)
throws XPathFunctionException
{
return Collections.EMPTY_SET;
}
public void setArguments(List args)
{
this.args = args;
}
public boolean matches(Node context)
{
Object ret = evaluate(context, 1, 1);
return !((Collection) ret).isEmpty();
}
public Object evaluate(Node context, int pos, int len)
{
int arity = args.size();
List values = new ArrayList(arity);
for (int i = 0; i < arity; i++)
{
Expr arg = (Expr) args.get(i);
values.add(arg.evaluate(context, pos, len));
}
QName keyName = QName.valueOf(_string(context, values.get(0)));
String uri = keyName.getNamespaceURI();
String prefix = keyName.getPrefix();
if ((uri == null || uri.length() == 0) &&
(prefix != null && prefix.length() > 0))
{
uri = stylesheet.getNamespaceURI(prefix);
if (uri != null && uri.length() > 0)
{
String localName = keyName.getLocalPart();
keyName = new QName(uri, localName, prefix);
}
}
Collection keySet = new LinkedList();
for (Iterator i = stylesheet.keys.iterator(); i.hasNext(); )
{
Key key = (Key) i.next();
if (key.name.equals(keyName))
{
keySet.add(key);
}
}
Object target = values.get(1);
Collection acc = new LinkedHashSet();
Document doc = (context instanceof Document) ? (Document) context :
context.getOwnerDocument();
if (target instanceof Collection)
{
for (Iterator i = ((Collection) target).iterator(); i.hasNext(); )
{
String val = Expr.stringValue((Node) i.next());
addKeyNodes(doc, keySet, val, acc);
}
}
else
{
String val = Expr._string(context, target);
addKeyNodes(doc, keySet, val, acc);
}
List ret = new ArrayList(acc);
Collections.sort(ret, documentOrderComparator);
return ret;
}
final void addKeyNodes(Node node, Collection keySet,
String value, Collection acc)
{
addKeyNodeIfMatch(node, keySet, value, acc);
for (Node ctx = node.getFirstChild(); ctx != null;
ctx = ctx.getNextSibling())
{
addKeyNodes(ctx, keySet, value, acc);
}
}
final void addKeyNodeIfMatch(Node node, Collection keySet,
String value, Collection acc)
{
for (Iterator i = keySet.iterator(); i.hasNext(); )
{
Key key = (Key) i.next();
if (key.match.matches(node))
{
Object eval = key.use.evaluate(node, 1, 1);
if (eval instanceof Collection)
{
for (Iterator j = ((Collection) eval).iterator();
j.hasNext(); )
{
String keyValue = Expr.stringValue((Node) j.next());
if (value.equals(keyValue))
{
acc.add(node);
return;
}
}
}
else
{
String keyValue = Expr._string(node, eval);
if (value.equals(keyValue))
{
acc.add(node);
return;
}
}
}
}
}
public Expr clone(Object context)
{
Stylesheet s = stylesheet;
if (context instanceof Stylesheet)
{
s = (Stylesheet) context;
}
KeyFunction f = new KeyFunction(s);
int len = args.size();
List args2 = new ArrayList(len);
for (int i = 0; i < len; i++)
{
args2.add(((Expr) args.get(i)).clone(context));
}
f.setArguments(args2);
return f;
}
}