KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > icl > saxon > functions > Extensions


1 package com.icl.saxon.functions;
2 import com.icl.saxon.*;
3 import com.icl.saxon.om.*;
4 import com.icl.saxon.tinytree.TinyBuilder;
5 import com.icl.saxon.tree.AttributeCollection;
6 import com.icl.saxon.expr.*;
7 import com.icl.saxon.output.*;
8 import com.icl.saxon.pattern.AnyNodeTest;
9 import com.icl.saxon.om.Axis;
10 import javax.xml.transform.TransformerException;
11 import java.util.*;
12 import java.text.*;
13 import org.w3c.xsl.XSLTContext;
14
15 /**
16 * This class implements functions that are supplied as standard with SAXON,
17 * but which are not defined in the XSLT or XPath specifications. <p>
18 *
19 * To invoke these functions, use a function call of the form prefix:name() where
20 * name is the method name, and prefix maps to a URI such as
21 * http://icl.com/saxon/com.icl.saxon.functions.Extensions (only the part
22 * of the URI after the last slash is important).
23 */

24
25
26
27 public class Extensions {
28
29
30     public static void pauseTracing(Context c) {
31         c.getController().pauseTracing(true);
32     }
33     public static void resumeTracing(Context c) {
34         c.getController().pauseTracing(false);
35     }
36     
37     /**
38     * Convert a result tree fragment to a node-set. This simply marks a result
39     * tree fragment as being available for general use.
40     */

41
42     public static NodeSetValue nodeSet(Context c, Value frag) throws XPathException {
43         if (frag instanceof SingletonNodeSet) {
44             ((SingletonNodeSet)frag).allowGeneralUse();
45         }
46         if (frag instanceof NodeSetValue) {
47             return (NodeSetValue)frag;
48         } else {
49             TextFragmentValue v =
50                 new TextFragmentValue(frag.asString(), "", c.getController());
51             v.allowGeneralUse();
52             return v;
53         }
54     }
55
56     /**
57     * Alternative spelling (allows "nodeset()")
58     */

59     
60     public static NodeSetValue nodeset(Context c, Value frag) throws XPathException {
61         return nodeSet(c, frag);
62     }
63     
64     /**
65     * Return the system identifier of the context node
66     */

67
68     public static String systemId(Context c) throws XPathException {
69         return c.getContextNodeInfo().getSystemId();
70     }
71
72     /**
73     * Return the line number of the context node.
74     * This must be returned as a double to meet the calling requirements for extension functions.
75     */

76
77     public static double lineNumber(Context c) throws XPathException {
78         return c.getContextNodeInfo().getLineNumber();
79     }
80
81     /**
82     * Return the base URI of the context node
83     */

84
85     public static String baseUri(Context c) throws XPathException {
86         return c.getContextNodeInfo().getBaseURI();
87     }
88
89     /**
90     * Return the intersection of two node-sets
91     * @param p1 The first node-set
92     * @param p2 The second node-set
93     * @return A node-set containing all nodes that are in both p1 and p2
94     */

95
96     public static NodeEnumeration intersection(Context c, NodeEnumeration p1, NodeEnumeration p2) throws XPathException {
97         return new IntersectionEnumeration(p1, p2, c.getController());
98     }
99
100     /**
101     * Return the difference of two node-sets
102     * @param p1 The first node-set
103     * @param p2 The second node-set
104     * @return A node-set containing all nodes that are in p1 and not in p2
105     */

106
107     public static NodeEnumeration difference(Context c, NodeEnumeration p1, NodeEnumeration p2) throws XPathException {
108         return new DifferenceEnumeration(p1, p2, c.getController());
109     }
110
111     /**
112     * Determine whether two node-sets contain the same nodes
113     * @param p1 The first node-set
114     * @param p2 The second node-set
115     * @return true if p1 and p2 contain the same set of nodes
116     */

117
118     public static boolean hasSameNodes(Context context, NodeEnumeration p1, NodeEnumeration p2) throws XPathException {
119         NodeEnumeration e1 = p1;
120         NodeEnumeration e2 = p2;
121         Controller controller = context.getController();
122         if (!e1.isSorted()) {
123             e1 = (new NodeSetExtent(e1, controller)).sort().enumerate();
124         }
125         if (!e2.isSorted()) {
126             e2 = (new NodeSetExtent(e2, controller)).sort().enumerate();
127         }
128         while (e1.hasMoreElements()) {
129             if (!e2.hasMoreElements()) {
130                 return false;
131             }
132             if (!e1.nextElement().isSameNode(e2.nextElement())) {
133                 return false;
134             }
135         }
136         if (e2.hasMoreElements()) {
137             return false;
138         }
139         return true;
140     }
141
142
143     /**
144     * Return the value of the second argument if the first is true, or the third argument
145     * otherwise. Note that all three arguments are evaluated.
146     * @param test A value treated as a boolean
147     * @param thenValue Any value
148     * @param elseValue Any value
149     * @return (test ? thenValue : elseValue)
150     */

151
152     public static Value IF (Value test, Value thenValue, Value elseValue ) throws XPathException {
153         return ( test.asBoolean() ? thenValue : elseValue );
154     }
155
156     /**
157     * Evaluate the expression supplied in the first argument as a string
158     */

159
160     public static Value evaluate (Context c, String expr) throws XPathException {
161         StaticContext env = c.getStaticContext().makeRuntimeContext(
162                                         c.getController().getNamePool());
163         Expression e = Expression.make(expr, env);
164         return e.evaluate(c);
165     }
166
167     /**
168     * Evaluate the stored expression supplied in the first argument
169     */

170
171     public static Value eval (Context c, Expression expr) throws XPathException {
172         return expr.evaluate(c);
173     }
174
175     /**
176     * Return an object representing a stored expression,
177     * from the string supplied in the first argument.
178     */

179
180     public static Value expression (Context c, String expr) throws XPathException {
181         StaticContext env = c.getStaticContext().makeRuntimeContext(
182                                         c.getController().getNamePool());
183         Expression e1 = Expression.make(expr, env);
184         // substitute values of variables
185
Expression e2 = e1.reduce(Context.VARIABLES, c).simplify();
186         return new ObjectValue(e2);
187     }
188
189     /**
190     * Total a stored expression over a set of nodes
191     */

192
193     public static double sum (Context context,
194                               NodeEnumeration nsv,
195                               Expression expression) throws XPathException {
196         double total = 0.0;
197         Context c = context.newContext();
198         NodeEnumeration v;
199         if (nsv instanceof LastPositionFinder) {
200             v = nsv;
201         } else {
202             v = new LookaheadEnumerator(nsv);
203         }
204         c.setLastPositionFinder((LastPositionFinder)v);
205         int pos = 1;
206         while (v.hasMoreElements()) {
207             c.setContextNode(v.nextElement());
208             c.setPosition(pos++);
209             double x = expression.evaluateAsNumber(c);
210             total += x;
211         }
212         return total;
213     }
214
215     /**
216     * Get the maximum numeric value of the string-value of each of a set of nodes
217     */

218
219     public static double max (NodeEnumeration nsv) throws XPathException {
220         return com.icl.saxon.exslt.Math.max(nsv);
221     }
222
223
224     /**
225     * Get the maximum numeric value of a stored expression over a set of nodes
226     */

227
228     public static double max (Context context,
229                               NodeEnumeration nsv,
230                               Expression expression) throws XPathException {
231         double max = Double.NEGATIVE_INFINITY;
232         Context c = context.newContext();
233         NodeEnumeration v;
234         if (nsv instanceof LastPositionFinder) {
235             v = nsv;
236         } else {
237             v = new LookaheadEnumerator(nsv);
238         }
239         c.setLastPositionFinder((LastPositionFinder)v);
240         int pos = 1;
241         while (v.hasMoreElements()) {
242             c.setContextNode(v.nextElement());
243             c.setPosition(pos++);
244             double x = expression.evaluateAsNumber(c);
245             if (x>max) max = x;
246         }
247         return max;
248     }
249
250     /**
251     * Get the minimum numeric value of the string-value of each of a set of nodes
252     */

253
254     public static double min (NodeEnumeration nsv) throws XPathException {
255         return com.icl.saxon.exslt.Math.min(nsv);
256     }
257
258     /**
259     * Get the minimum numeric value of a stored expression over a set of nodes
260     */

261
262     public static double min (Context context,
263                               NodeEnumeration nsv,
264                               Expression expression) throws XPathException {
265         double min = Double.POSITIVE_INFINITY;
266         Context c = context.newContext();
267         NodeEnumeration v;
268         if (nsv instanceof LastPositionFinder) {
269             v = nsv;
270         } else {
271             v = new LookaheadEnumerator(nsv);
272         }
273         c.setLastPositionFinder((LastPositionFinder)v);
274         int pos = 1;
275         while (v.hasMoreElements()) {
276             c.setContextNode(v.nextElement());
277             c.setPosition(pos++);
278             double x = expression.evaluateAsNumber(c);
279             if (x<min) min = x;
280         }
281         return min;
282     }
283
284     /**
285     * Get the node with maximum numeric value of the string-value of each of a set of nodes
286     */

287
288     public static NodeSetValue highest (Context c, NodeEnumeration nsv) throws XPathException {
289         return com.icl.saxon.exslt.Math.highest(c, nsv);
290     }
291
292
293     /**
294     * Get the maximum numeric value of a stored expression over a set of nodes
295     */

296
297     public static NodeEnumeration highest (Context context,
298                                         NodeEnumeration nsv,
299                                         Expression expression) throws XPathException {
300         double max = Double.NEGATIVE_INFINITY;
301         Context c = context.newContext();
302         NodeInfo highest = null;
303         NodeEnumeration v;
304         if (nsv instanceof LastPositionFinder) {
305             v = nsv;
306         } else {
307             v = new LookaheadEnumerator(nsv);
308         }
309         c.setLastPositionFinder((LastPositionFinder)v);
310         int pos = 1;
311         while (v.hasMoreElements()) {
312             c.setContextNode(v.nextElement());
313             c.setPosition(pos++);
314             double x = expression.evaluateAsNumber(c);
315             if (x>max) {
316                 max = x;
317                 highest = c.getContextNodeInfo();
318             }
319         }
320         return new SingletonEnumeration(highest);
321     }
322
323     /**
324     * Get the node with minimum numeric value of the string-value of each of a set of nodes
325     */

326
327     public static NodeSetValue lowest (Context c, NodeEnumeration nsv) throws XPathException {
328         return com.icl.saxon.exslt.Math.lowest(c, nsv);
329     }
330
331     /**
332     * Get the node with minimum numeric value of a stored expression over a set of nodes
333     */

334
335     public static NodeEnumeration lowest (Context context,
336                                        NodeEnumeration nsv,
337                                        Expression expression) throws XPathException {
338         double min = Double.POSITIVE_INFINITY;
339         Context c = context.newContext();
340         NodeInfo lowest = null;
341         NodeEnumeration v;
342         if (nsv instanceof LastPositionFinder) {
343             v = nsv;
344         } else {
345             v = new LookaheadEnumerator(nsv);
346         }
347         c.setLastPositionFinder((LastPositionFinder)v);
348         int pos = 1;
349         while (v.hasMoreElements()) {
350             c.setContextNode(v.nextElement());
351             c.setPosition(pos++);
352             double x = expression.evaluateAsNumber(c);
353             if (x<min) {
354                 min = x;
355                 lowest = c.getContextNodeInfo();
356             }
357         }
358         return new SingletonEnumeration(lowest);
359     }
360
361     /**
362     * Given a node-set, return a subset that includes only nodes with distinct string-values
363     */

364
365     public static NodeEnumeration distinct(Context context, NodeEnumeration in) throws XPathException {
366         return new DistinctEnumeration(in, context.getController());
367     }
368
369     /**
370     * Given a node-set, return a subset that includes only nodes with distinct string-values
371     * for the supplied expression
372     */

373
374     public static NodeEnumeration distinct(Context context,
375                                         NodeEnumeration in,
376                                         Expression exp) throws XPathException {
377         return new DistinctEnumeration(context, in, exp);
378     }
379
380     /**
381     * Evaluate the transitive closure of a node-set expression
382     */

383
384     public static NodeEnumeration closure (Context c,
385             NodeEnumeration enum, Expression expr) throws XPathException {
386                 
387         NodeEnumeration result = EmptyEnumeration.getInstance();
388         Controller controller = c.getController();
389         while(enum.hasMoreElements()) {
390             NodeInfo node = enum.nextElement();
391             Context c2 = c.newContext();
392             c2.setContextNode(node);
393             c2.setCurrentNode(node);
394             c2.setPosition(1);
395             c2.setLast(1);
396             NodeEnumeration next =
397                 new UnionEnumeration(
398                     new SingletonEnumeration(node),
399                     closure(c2, expr.enumerate(c2, false), expr),
400                     controller);
401             result = new UnionEnumeration(result, next, controller);
402         }
403         return result;
404     }
405
406     /**
407     * Get the nodes that satisfy the given expression, up to and excluding the first one
408     * (in document order) that doesn't
409     */

410
411     public static NodeEnumeration leading (Context context,
412                          NodeEnumeration in, Expression exp) throws XPathException {
413         return new FilterEnumerator(in, exp, context.newContext(), true);
414     }
415
416     /**
417     * Find all the nodes in ns1 that are before the last node in ns2.
418     * Return empty set if ns2 is empty,
419     */

420
421     public static NodeSetValue before (
422                                  Context context,
423                                  NodeSetValue ns1,
424                                  NodeSetValue ns2) throws XPathException {
425
426         NodeInfo test = null;
427         NodeEnumeration enum2 = ns2.enumerate();
428         while (enum2.hasMoreElements()) {
429             test = enum2.nextElement();
430         }
431         if (test==null) {
432             return new EmptyNodeSet();
433         }
434         Controller controller = context.getController();
435                 
436         Vector v = new Vector();
437         NodeEnumeration enum = ns1.enumerate();
438         while (enum.hasMoreElements()) {
439             NodeInfo node = enum.nextElement();
440             if (controller.compare(node, test) < 0) {
441                 v.addElement(node);
442             } else {
443                 break;
444             }
445         }
446         return new NodeSetExtent(v, controller);
447
448     }
449
450     /**
451     * Find all the nodes in ns1 that are after the first node in ns2.
452     * Return empty set if ns2 is empty,
453     */

454
455     public static NodeSetValue after (
456                      Context context,
457                      NodeSetValue ns1, NodeSetValue ns2) throws XPathException {
458
459         NodeInfo test = ns2.getFirst();
460         if (test==null) {
461             return new EmptyNodeSet();
462         }
463         Controller controller = context.getController();
464             
465         Vector v = new Vector();
466         NodeEnumeration enum = ns1.enumerate();
467         boolean pastLimit = false;
468         while (enum.hasMoreElements()) {
469             NodeInfo node = enum.nextElement();
470             if (pastLimit) {
471                 v.addElement(node);
472             } else if (controller.compare(node, test) > 0) {
473                 pastLimit = true;
474                 v.addElement(node);
475             }
476         }
477         return new NodeSetExtent(v, controller);
478
479     }
480
481     /**
482     * Test whether node-set contains a node that satisfies a given condition
483     */

484
485     public static boolean exists (Context context,
486                               NodeEnumeration nsv,
487                               Expression expression) throws XPathException {
488         return new FilterEnumerator(nsv, expression, context.newContext(), false)
489                     .hasMoreElements();
490     }
491
492     /**
493     * Test whether all nodes in a node-set satisfy a given condition
494     */

495
496     public static boolean forAll (Context context,
497                               NodeEnumeration nsv,
498                               Expression expression) throws XPathException {
499         Not notexp = new Not();
500         notexp.addArgument(expression);
501         return !(new FilterEnumerator(nsv, notexp, context.newContext(), false)
502                     .hasMoreElements());
503     }
504
505
506     /**
507     * Return a node-set whose nodes have string-values "1", "2", ... "n"
508     */

509
510     public static NodeEnumeration range(Context context, double start, double finish) throws XPathException {
511         int a = (int)Round.round(start);
512         int b = (int)Round.round(finish);
513         
514         try {
515             TinyBuilder builder = new TinyBuilder();
516             NamePool pool = context.getController().getNamePool();
517             int[] namespaces = new int[1];
518             namespaces[0] = pool.getNamespaceCode("saxon", Namespace.SAXON);
519             int saxonRange = pool.allocate("saxon", Namespace.SAXON, "range");
520             builder.setNamePool(pool);
521             builder.startDocument();
522             AttributeCollection emptyAtts = new AttributeCollection(pool);
523             
524             for (int i=a; i<=b; i++) {
525                 builder.startElement(saxonRange, emptyAtts, namespaces, 1);
526                 String n = i+"";
527                 builder.characters(n.toCharArray(), 0, n.length());
528                 builder.endElement(saxonRange);
529             }
530         
531             builder.endDocument();
532             DocumentInfo doc = builder.getCurrentDocument();
533             return doc.getEnumeration(Axis.CHILD, AnyNodeTest.getInstance());
534             
535         } catch (TransformerException err) {
536             throw new XPathException(err);
537         }
538
539     }
540
541     /**
542     * Return a node-set by tokenizing a supplied string. Tokens are delimited by any sequence of
543     * whitespace characters.
544     */

545
546     public static NodeEnumeration tokenize(Context context, String s) throws XPathException {
547
548         try {
549             Builder builder = context.getController().makeBuilder();
550             NamePool pool = context.getController().getNamePool();
551             builder.startDocument();
552             int[] namespaces = new int[1];
553             namespaces[0] = pool.getNamespaceCode("saxon", Namespace.SAXON);
554             int saxonToken = pool.allocate("saxon", Namespace.SAXON, "token");
555             AttributeCollection emptyAtts = new AttributeCollection(pool);
556     
557             StringTokenizer st = new StringTokenizer(s);
558             while (st.hasMoreTokens()) {
559                 builder.startElement(saxonToken, emptyAtts, namespaces, 1);
560                 String n = st.nextToken();
561                 builder.characters(n.toCharArray(), 0, n.length());
562                 builder.endElement(saxonToken);
563             }
564                     
565             builder.endDocument();
566             DocumentInfo doc = builder.getCurrentDocument();
567             return doc.getEnumeration(Axis.CHILD, AnyNodeTest.getInstance());
568         } catch (TransformerException err) {
569             throw new XPathException(err);
570         }
571     }
572
573     /**
574     * Return a node-set by tokenizing a supplied string. The argument delim is a String, any character
575     * in this string is considered to be a delimiter character, and any sequence of delimiter characters
576     * acts as a separator between tokens.
577     */

578
579     public static NodeEnumeration tokenize(Context context, String s, String delim) throws XPathException {
580         try {
581             Builder builder = context.getController().makeBuilder();
582             NamePool pool = context.getController().getNamePool();
583             builder.setNamePool(pool);
584             builder.startDocument();
585             int[] namespaces = new int[1];
586             namespaces[0] = pool.getNamespaceCode("saxon", Namespace.SAXON);
587             int saxonToken = pool.allocate("saxon", Namespace.SAXON, "token");
588             AttributeCollection emptyAtts = new AttributeCollection(pool);
589     
590             StringTokenizer st = new StringTokenizer(s, delim);
591             while (st.hasMoreTokens()) {
592                 builder.startElement(saxonToken, emptyAtts, namespaces, 1);
593                 String n = st.nextToken();
594                 builder.characters(n.toCharArray(), 0, n.length());
595                 builder.endElement(saxonToken);
596             }
597                     
598             builder.endDocument();
599             DocumentInfo doc = builder.getCurrentDocument();
600             return doc.getEnumeration(Axis.CHILD, AnyNodeTest.getInstance());
601         } catch (TransformerException err) {
602             throw new XPathException(err);
603         }
604     }
605
606
607     /**
608     * Return an XPath expression that identifies the current node
609     */

610
611     public static String path(Context c) throws XPathException {
612         return Navigator.getPath(c.getContextNodeInfo());
613     }
614
615     /**
616     * Array of names of node types. You can index into this with the numeric node type.
617     */

618     
619     private static final String[] NODE_TYPE_NAMES =
620         {"Node", "Element", "Attribute", "Text", "?", "?", "?",
621             "Processing Instruction", "Comment", "Root", "?", "?", "?", "Namespace"};
622
623     /**
624     * A diagnostic function to print the contents of a node-set
625     */

626     
627     public static String showNodeset(Context c, NodeSetValue in) throws XPathException {
628         System.err.println("Node-set contents at line " + c.getStaticContext().getLineNumber() + " [");
629         NodeEnumeration enum = in.enumerate(c, true);
630         int count = 0;
631         while (enum.hasMoreElements()) {
632             count++;
633             NodeInfo next = enum.nextElement();
634             String typeName = NODE_TYPE_NAMES[next.getNodeType()];
635             System.err.println(" " + typeName + " " +
636                                  next.getDisplayName() + " " +
637                                  Navigator.getPath(next) + " " +
638                                  next.generateId());
639         }
640         System.err.println("] (Total number of nodes: " + count + ")");
641         return "";
642     }
643                                  
644
645     /**
646     * Test whether an encapsulated Java object is null
647     */

648
649     public static boolean isNull(Object x) throws XPathException {
650         return x==null;
651     }
652
653
654     /**
655     * Save a value associated with the context node
656     */

657
658     public static void setUserData(Context c, String name, Value value) throws XPathException {
659             // System.err.println("Set user data " + name + " on " + c.getContextNode().getPath() + " = " + value);
660
c.getController().setUserData(
661             (c.getContextNodeInfo()), name, value);
662     }
663
664     /**
665     * Retrieve a value associated with the context node
666     */

667
668     public static Value getUserData(Context c, String name) throws XPathException {
669         Object o = c.getController().getUserData(
670                         (c.getContextNodeInfo()), name);
671             // System.err.println("Get user data " + name + " on " + c.getContextNode().getPath() + " = " + o);
672
if (o==null) return new StringValue("");
673         if (o instanceof Value) return (Value)o;
674         return new ObjectValue(o);
675     }
676
677     /**
678     * Return the Context object
679     */

680     
681     public static Context getContext(Context c) {
682         return c;
683     }
684     
685     /**
686     * Get a pseudo-attribute of a processing instruction. Return an empty string
687     * if the context node is not a processing instruction, or if the pseudo-attribute
688     * is not present. Character references and built-in entity references are expanded
689     */

690     
691     public static String getPseudoAttribute(Context c, String name) {
692         NodeInfo pi = c.getContextNodeInfo();
693         if (pi.getNodeType() != NodeInfo.PI) return "";
694         String val = ProcInstParser.getPseudoAttribute(pi.getStringValue(), name);
695         if (val==null) return "";
696         return val;
697     }
698         
699         
700
701 }
702
703
704
705
706
707 //
708
// The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
709
// you may not use this file except in compliance with the License. You may obtain a copy of the
710
// License at http://www.mozilla.org/MPL/
711
//
712
// Software distributed under the License is distributed on an "AS IS" basis,
713
// WITHOUT WARRANTY OF ANY KIND, either express or implied.
714
// See the License for the specific language governing rights and limitations under the License.
715
//
716
// The Original Code is: all this file.
717
//
718
// The Initial Developer of the Original Code is
719
// Michael Kay of International Computers Limited (mhkay@iclway.co.uk).
720
//
721
// Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
722
//
723
// Contributor(s): none.
724
//
725
Popular Tags