diff options
Diffstat (limited to 'libjava/gnu/xml/transform/NodeNumberNode.java')
-rw-r--r-- | libjava/gnu/xml/transform/NodeNumberNode.java | 261 |
1 files changed, 261 insertions, 0 deletions
diff --git a/libjava/gnu/xml/transform/NodeNumberNode.java b/libjava/gnu/xml/transform/NodeNumberNode.java new file mode 100644 index 00000000000..76f8d7eea3d --- /dev/null +++ b/libjava/gnu/xml/transform/NodeNumberNode.java @@ -0,0 +1,261 @@ +/* NodeNumberNode.java -- + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +02111-1307 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +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.Document; +import org.w3c.dom.Node; +import gnu.xml.xpath.Expr; +import gnu.xml.xpath.NodeTypeTest; +import gnu.xml.xpath.Pattern; +import gnu.xml.xpath.Selector; +import gnu.xml.xpath.Test; +import gnu.xml.xpath.UnionExpr; + +/** + * A template node representing the XSL <code>number</code> instruction + * with no <code>value</code> expression, i.e. the value is computed from + * the document position of the context node. + * + * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a> + */ +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 + { + /*if (from != null) + { + Object ret = from.evaluate(context, pos, len); + if (ret instanceof Collection) + { + Collection ns = (Collection) ret; + if (ns.size() > 0) + { + List list = new ArrayList(ns); + Collections.sort(list, documentOrderComparator); + context = (Node) list.get(0); + } + else + { + return new int[0]; + } + } + else + { + return new int[0]; + } + }*/ + 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; + } + +} |