NodeNumberNode.java [plain text]
package gnu.xml.transform;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import javax.xml.transform.TransformerException;
import org.w3c.dom.Node;
import gnu.xml.xpath.Expr;
import gnu.xml.xpath.Pattern;
import gnu.xml.xpath.Selector;
import gnu.xml.xpath.UnionExpr;
final class NodeNumberNode
extends AbstractNumberNode
{
static final int SINGLE = 0;
static final int MULTIPLE = 1;
static final int ANY = 2;
final int level;
final Pattern count;
final Pattern from;
NodeNumberNode(TemplateNode children, TemplateNode next,
int level, Pattern count, Pattern from,
TemplateNode format, String lang,
int letterValue, String groupingSeparator, int groupingSize)
{
super(children, next, format, lang, letterValue, groupingSeparator,
groupingSize);
this.level = level;
this.count = count;
this.from = from;
}
TemplateNode clone(Stylesheet stylesheet)
{
return new NodeNumberNode((children == null) ? null :
children.clone(stylesheet),
(next == null) ? null :
next.clone(stylesheet),
level,
(count == null) ? null :
(Pattern) count.clone(stylesheet),
(from == null) ? from :
(Pattern) from.clone(stylesheet),
format, lang, letterValue,
groupingSeparator, groupingSize);
}
int[] compute(Stylesheet stylesheet, Node context, int pos, int len)
throws TransformerException
{
Node current = context;
switch (level)
{
case SINGLE:
if (from == null)
{
while (context != null && !countMatches(current, context))
{
context = context.getParentNode();
}
}
else
{
while (context != null && !countMatches(current, context) &&
!fromMatches(context))
{
context = context.getParentNode();
}
}
return (context == null) ? new int[0] :
new int[] { (context == current) ? pos : getIndex(current, context) };
case MULTIPLE:
List ancestors = new ArrayList();
while (context != null)
{
if (countMatches(current, context))
{
if (from == null || fromMatches(context))
{
ancestors.add(context);
}
}
context = context.getParentNode();
}
Collections.sort(ancestors, documentOrderComparator);
int[] ret = new int[ancestors.size()];
for (int i = 0; i < ret.length; i++)
{
ret[i] = getIndex(current, (Node) ancestors.get(i));
}
return ret;
case ANY:
Expr preceding = new Selector(Selector.PRECEDING,
Collections.EMPTY_LIST);
Expr ancestorOrSelf = new Selector(Selector.ANCESTOR_OR_SELF,
Collections.EMPTY_LIST);
Expr any = new UnionExpr(preceding, ancestorOrSelf);
Object eval = any.evaluate(context, pos, len);
if (eval instanceof Collection)
{
Collection ns = (Collection) eval;
List candidates = new ArrayList();
for (Iterator i = ns.iterator(); i.hasNext(); )
{
Node candidate = (Node) i.next();
if (countMatches(current, candidate))
{
candidates.add(candidate);
if (from != null && from.matches(candidate))
{
break;
}
}
}
return new int[] { candidates.size() };
}
return new int[0];
default:
throw new TransformerException("invalid level");
}
}
boolean countMatches(Node current, Node node)
{
if (count == null)
{
int cnt = current.getNodeType();
int nnt = node.getNodeType();
if (cnt != nnt)
{
return false;
}
if (nnt == Node.ELEMENT_NODE || nnt == Node.ATTRIBUTE_NODE)
{
String curi = current.getNamespaceURI();
String nuri = node.getNamespaceURI();
if ((curi == null && nuri != null) ||
(curi != null && !curi.equals(nuri)))
{
return false;
}
String cn = current.getLocalName();
String nn = current.getLocalName();
if (!cn.equals(nn))
{
return false;
}
}
return true;
}
else
{
return count.matches(node);
}
}
boolean fromMatches(Node node)
{
for (Node ctx = node.getParentNode(); ctx != null;
ctx = ctx.getParentNode())
{
if (from.matches(ctx))
{
return true;
}
}
return false;
}
int getIndex(Node current, Node node)
{
int index = 0;
do
{
do
{
node = node.getPreviousSibling();
}
while (node != null && !countMatches(current, node));
index++;
}
while (node != null);
return index;
}
}