KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > gnu > xquery > util > NodeUtils


1 // Copyright (c) 2005, 2006 Per M.A. Bothner.
2
// This is free software; for terms and warranty disclaimer see ./COPYING.
3

4 package gnu.xquery.util;
5 import gnu.mapping.*;
6 import gnu.xml.*;
7 import gnu.kawa.xml.*;
8 import gnu.lists.*;
9 import java.util.Stack JavaDoc;
10 import java.net.*;
11 import gnu.text.URI_utils;
12 import gnu.expr.PrimProcedure;
13 import gnu.bytecode.ClassType;
14 import gnu.xquery.lang.XQuery;
15
16 public class NodeUtils
17 {
18   public static String JavaDoc name (Object JavaDoc node)
19   {
20     if (node == Values.empty || node == null)
21       return "";
22     Object JavaDoc name = NodeName.nodeName(node);
23     if (name == null || name == Values.empty)
24       return "";
25     return name.toString();
26   }
27
28   public static String JavaDoc localName (Object JavaDoc node)
29   {
30     if (node == Values.empty || node == null)
31       return "";
32     if (! (node instanceof KNode))
33       throw new WrongType("local-name", 1, node, "node()?");
34     Object JavaDoc name = NodeName.nodeName(node);
35     if (name == null || name == Values.empty)
36       return "";
37     return ((Symbol) name).getName();
38   }
39
40   public static Object JavaDoc namespaceURI (Object JavaDoc node)
41   {
42     if (node == Values.empty || node == null)
43       return "";
44     if (! (node instanceof KNode))
45       throw new WrongType("namespace-uri", 1, node, "node()?");
46     Object JavaDoc name = NodeName.nodeName(node);
47     if (name == null || name == Values.empty)
48       return "";
49     return QNameUtils.namespaceURIFromQName(name);
50   }
51
52   public static void prefixesFromNodetype (XName name, Consumer out)
53   {
54     NamespaceBinding bindings = ((XName) name).getNamespaceNodes();
55     for (NamespaceBinding ns = bindings;
56          ns != null;
57          ns = ns.getNext())
58       {
59         String JavaDoc prefix = ns.getPrefix();
60         // Check for duplicates. This is an O(n^2) algorthm, but these
61
// lists are usually quite short ...
62
for (NamespaceBinding ns2 = bindings; ; ns2 = ns2.getNext())
63            {
64              if (ns2 == ns)
65                {
66                  out.writeObject(prefix == null ? "" : prefix);
67                  break;
68                }
69              if (ns2.getPrefix() == prefix)
70                {
71                  // Previously written.
72
break;
73                }
74            }
75       }
76   }
77
78   public static void inScopePrefixes$X (Object JavaDoc node, CallContext ctx)
79   {
80     //if (node instanceof KElement)
81
{
82         KElement element = (KElement) node;
83         Object JavaDoc type = element.sequence.getNextTypeObject(element.ipos);
84         if (type instanceof XName)
85           prefixesFromNodetype((XName) type, ctx.consumer);
86         else
87           ctx.consumer.writeObject("xml");
88       }
89   }
90
91   public static void data$X (Object JavaDoc arg, CallContext ctx)
92   {
93     Consumer out = ctx.consumer;
94     if (arg instanceof Values)
95       {
96         Values vals = (Values) arg;
97         int ipos = vals.startPos();
98         while ((ipos = vals.nextPos(ipos)) != 0)
99           out.writeObject(KNode.atomicValue(vals.getPosPrevious(ipos)));
100       }
101     else
102       out.writeObject(KNode.atomicValue(arg));
103   }
104
105   /** Return the root node of the argument. */
106   public static Object JavaDoc root (Object JavaDoc arg)
107   {
108     if (arg == null || arg == Values.empty)
109       return arg;
110     if (! (arg instanceof KNode))
111       throw new WrongType("root", 1, arg, "node()?");
112     KNode node = (KNode) arg;
113     return Nodes.root((NodeTree) node.sequence, node.getPos());
114   }
115
116   public static String JavaDoc getLang (KNode node)
117   {
118     NodeTree seq = (NodeTree) node.sequence;
119     int attr = seq.ancestorAttribute(node.ipos,
120                                      gnu.xml.NamespaceBinding.XML_NAMESPACE,
121                                      "lang");
122     if (attr == 0)
123       return null;
124     else
125       return KNode.getNodeValue(seq, attr);
126   }
127
128   public static boolean lang (Object JavaDoc testlang, Object JavaDoc node)
129   {
130     String JavaDoc teststr;
131     if (testlang == null || testlang == Values.empty)
132       teststr = "";
133     else
134       teststr = TextUtils.stringValue(testlang);
135     String JavaDoc lang = getLang((KNode) node);
136     if (lang == null)
137       return false;
138     int langlen = lang.length();
139     int testlen = teststr.length();
140     if (langlen > testlen && lang.charAt(testlen) == '-')
141       lang = lang.substring(0, testlen);
142     return lang.equalsIgnoreCase(teststr);
143   }
144
145   public static Object JavaDoc documentUri (Object JavaDoc arg)
146   {
147     if (arg == null || arg == Values.empty)
148       return arg;
149     if (! (arg instanceof KNode))
150       throw new WrongType("xs:document-uri", 1, arg, "node()?");
151     KNode node = (KNode) arg;
152     Object JavaDoc uri = ((NodeTree) node.sequence).documentUriOfPos(node.ipos);
153     return uri == null ? Values.empty : uri;
154   }
155
156   public static Object JavaDoc nilled (Object JavaDoc arg)
157   {
158     if (arg == null || arg == Values.empty)
159       return arg;
160     if (! (arg instanceof KNode))
161       throw new WrongType("nilled", 1, arg, "node()?");
162     if (! (arg instanceof KElement))
163       return Values.empty;
164     return Boolean.FALSE;
165   }
166
167   public static Object JavaDoc baseUri (Object JavaDoc arg)
168   {
169     if (arg == null || arg == Values.empty)
170       return arg;
171     if (! (arg instanceof KNode))
172       throw new WrongType("base-uri", 1, arg, "node()?");
173     Object JavaDoc uri = ((KNode) arg).baseURI();
174     return uri == null ? Values.empty : uri;
175   }
176
177   /* #ifdef JAVA5 */
178   // @SuppressWarnings("unchecked")
179
/* #endif */
180   /** Extract canditate IDREFs from arg.
181    * @return {@code null} (if no {@code IDREF}s);
182    * a {@code String} (if a single {@code IDREF});
183    * or a {@code Stack<String>} (if more than one {@code IDREF}s).
184    */

185   static Object JavaDoc getIDs (Object JavaDoc arg, Object JavaDoc collector)
186   {
187     if (arg instanceof KNode)
188       arg = KNode.atomicValue(arg);
189     if (arg instanceof Values)
190       {
191         Object JavaDoc[] ar = ((Values) arg).getValues();
192         for (int i = ar.length; --i >= 0; )
193           collector = getIDs(ar[i], collector);
194       }
195     else
196       {
197         String JavaDoc str = StringUtils.coerceToString(arg, "fn:id", 1, "");
198         int len = str.length();
199         int i = 0;
200         while (i < len)
201           {
202             char ch = str.charAt(i++);
203             if (Character.isWhitespace(ch))
204               continue;
205             int start = XName.isNameStart(ch) ? i - 1 : len;
206             while (i < len)
207               {
208                 ch = str.charAt(i);
209                 if (Character.isWhitespace(ch))
210                   break;
211                 i++;
212                 if (start < len && ! XName.isNamePart(ch))
213                   start = len;
214               }
215             if (start < len)
216               {
217                 String JavaDoc ref = str.substring(start, i);
218                 if (collector == null)
219                   collector = ref;
220                 else
221                   {
222                     Stack JavaDoc st;
223                     if (collector instanceof Stack JavaDoc)
224                       st = (Stack JavaDoc) collector;
225                     else
226                       {
227                         st = new Stack JavaDoc();
228                         st.push(collector);
229                         collector = st;
230                       }
231                     st.push(ref);
232                   }
233               }
234             i++;
235           }
236       }
237     return collector;
238   }
239
240   public static void id$X (Object JavaDoc arg1, Object JavaDoc arg2, CallContext ctx)
241   {
242     KNode node = (KNode) arg2;
243     NodeTree ntree = (NodeTree) node.sequence;
244     KDocument root
245       = (KDocument) Nodes.root(ntree, node.ipos);
246     Consumer out = ctx.consumer;
247     Object JavaDoc idrefs = getIDs(arg1, null);
248     if (idrefs == null)
249       return;
250     ntree.makeIDtableIfNeeded();
251     if (out instanceof PositionConsumer
252         && (idrefs instanceof String JavaDoc || out instanceof SortedNodes))
253       idScan(idrefs, ntree, (PositionConsumer) out);
254     else if (idrefs instanceof String JavaDoc)
255       {
256         int pos = ntree.lookupID((String JavaDoc) idrefs);
257         if (pos != -1)
258           out.writeObject(KNode.make(ntree, pos));
259       }
260     else
261       {
262         SortedNodes nodes = new SortedNodes();
263         idScan(idrefs, ntree, nodes);
264         Values.writeValues(nodes, out);
265       }
266   }
267
268   private static void idScan (Object JavaDoc ids, NodeTree seq, PositionConsumer out)
269   {
270     if (ids instanceof String JavaDoc)
271       {
272         int pos = seq.lookupID((String JavaDoc) ids);
273         if (pos != -1)
274           out.writePosition(seq, pos);
275       }
276     else if (ids instanceof Stack JavaDoc)
277       {
278         Stack JavaDoc st = (Stack JavaDoc) ids;
279         int n = st.size();
280         for (int i = 0; i < n; i++)
281           idScan(st.elementAt(i), seq, out);
282       }
283   }
284
285   public static Object JavaDoc idref (Object JavaDoc arg1, Object JavaDoc arg2)
286   {
287     KNode node = (KNode) arg2;
288     KDocument root
289       = (KDocument) Nodes.root((NodeTree) node.sequence, node.getPos());
290     return Values.empty;
291   }
292
293   /** Internal namespace used to manage cached collections. */
294   static String JavaDoc collectionNamespace = "http://gnu.org/kawa/cached-collections";
295
296   /** Add a uri-to-value binding that setSavedCollection can later return. */
297   public static void setSavedCollection (Object JavaDoc uri, Object JavaDoc value,
298                                          Environment env)
299   {
300     if (uri == null)
301       uri = "#default";
302     Symbol sym = Symbol.make(collectionNamespace, uri.toString());
303     env.put(sym, null, value);
304   }
305
306   /** Add a uri-to-value binding that setSavedCollection can later return. */
307   public static void setSavedCollection (Object JavaDoc uri, Object JavaDoc value)
308   {
309     setSavedCollection(uri, value, Environment.getCurrent());
310   }
311
312   /** Default resolver for fn:collection.
313    * Return nodes previously bound using setSavedCollection.
314    */

315   public static Object JavaDoc getSavedCollection (Object JavaDoc uri, Environment env)
316   {
317     if (uri == null)
318       uri = "#default";
319     Symbol sym = Symbol.make(collectionNamespace, uri.toString());
320     Object JavaDoc coll = env.get(sym, null, null);
321     if (coll == null)
322       throw new RuntimeException JavaDoc("collection '"+uri+"' not found");
323     return coll;
324   }
325
326   /** Default resolver for fn:collection.
327    * Return nodes previously bound using setSavedCollection.
328    */

329   public static Object JavaDoc getSavedCollection (Object JavaDoc uri)
330   {
331     return getSavedCollection(uri, Environment.getCurrent());
332   }
333
334   /** Symbol used to bind a collection resolver. */
335   public static final Symbol collectionResolverSymbol =
336     Symbol.make(XQuery.LOCAL_NAMESPACE, "collection-resolver", "qexo");
337
338   public static Object JavaDoc collection (Object JavaDoc uri, Object JavaDoc base)
339     throws Throwable JavaDoc
340   {
341     uri = resolve(uri, base, "collection");
342     Environment env = Environment.getCurrent();
343     Symbol rsym = NodeUtils.collectionResolverSymbol;
344     Object JavaDoc rvalue = env.get(rsym, null, null);
345     if (rvalue == null)
346       {
347         rvalue = env.get(Symbol.makeWithUnknownNamespace(rsym.getLocalName(),
348                                                            rsym.getPrefix()),
349                            null, null);
350       }
351     String JavaDoc str;
352     int colon;
353     if (rvalue == null)
354       {
355         return getSavedCollection(uri);
356       }
357     else if ((rvalue instanceof String JavaDoc || rvalue instanceof UntypedAtomic)
358              && (colon = (str = rvalue.toString()).indexOf(':')) > 0)
359       {
360         String JavaDoc cname = str.substring(0, colon);
361         String JavaDoc mname = str.substring(colon+1);
362         Class JavaDoc rclass;
363         try
364           {
365             rclass = Class.forName(cname);
366           }
367         catch (ClassNotFoundException JavaDoc ex)
368           {
369             throw new RuntimeException JavaDoc("invalid collection-resolver: class "+cname+" not found");
370           }
371         catch (Throwable JavaDoc ex)
372           {
373             throw new RuntimeException JavaDoc("invalid collection-resolver: "+ex);
374           }
375         ClassType rclassType = ClassType.make(cname);
376         rvalue = gnu.kawa.reflect.ClassMethods.apply(rclassType, mname, '\0', XQuery.instance);
377         if (rvalue == null)
378           throw new RuntimeException JavaDoc("invalid collection-resolver: no method "+mname+" in "+cname);
379       }
380     if (! (rvalue instanceof Procedure))
381       throw new RuntimeException JavaDoc("invalid collection-resolver: "+rvalue);
382     return ((Procedure) rvalue).apply1(uri);
383   }
384
385   static Object JavaDoc resolve (Object JavaDoc uri, Object JavaDoc base, String JavaDoc fname)
386     throws Throwable JavaDoc
387   {
388     if (! (uri instanceof URL))
389       {
390         if (! (uri instanceof java.io.File JavaDoc)
391             /* #ifdef use:java.net.URI */
392             && ! (uri instanceof URI)
393             /* #endif */
394             )
395           uri = StringUtils.coerceToString(uri, fname, 1, null);
396         if (uri == Values.empty || uri == null)
397           return null;
398         if (! URI_utils.isAbsolute(uri))
399           {
400             if (base == null)
401               base = CallContext.getInstance().getBaseUri();
402             uri = URI_utils.resolve(uri, base);
403           }
404       }
405     return uri;
406   }
407
408   /** Parse an XML document, caching the result.
409    * Only positive results are cached; failures are not.)
410    * This implements the standard XQuery <code>fn:doc</code> function.
411    */

412   public static Object JavaDoc docCached (Object JavaDoc uri, Object JavaDoc base)
413     throws Throwable JavaDoc
414   {
415     uri = resolve(uri, base, "doc");
416     if (uri == null)
417       return Values.empty;
418     return Document.parseCached(uri);
419   }
420
421   /** Check if an XML document is available, caching the result.
422    * Only positive results are cached; failures are not. Thus it is possible
423    * for a false result to be followed by a true result, but not vice versa.
424    * This implements the standard XQuery <code>fn:doc-available</code> function.
425    */

426   public static boolean availableCached (Object JavaDoc uri, Object JavaDoc base)
427     throws Throwable JavaDoc
428   {
429     uri = resolve(uri, base, "doc-available");
430     if (uri == null)
431       return false;
432     try
433       {
434         Document.parseCached(uri);
435         return true;
436       }
437     catch (Throwable JavaDoc ex)
438       {
439         return false;
440       }
441   }
442 }
443
Popular Tags