Normalize line endings.
[mono.git] / mcs / class / System.XML / Mono.Xml.Xsl / XslFunctions.cs
1 //
2 // XsltCompiledContext.cs
3 //
4 // Authors:
5 //      Ben Maurer (bmaurer@users.sourceforge.net)
6 //      Atsushi Enomoto (atsushi@ximian.com)
7 // (C) 2003 Ben Maurer
8 // (C) 2004 Atsushi Enomoto
9 //
10
11 //
12 // Permission is hereby granted, free of charge, to any person obtaining
13 // a copy of this software and associated documentation files (the
14 // "Software"), to deal in the Software without restriction, including
15 // without limitation the rights to use, copy, modify, merge, publish,
16 // distribute, sublicense, and/or sell copies of the Software, and to
17 // permit persons to whom the Software is furnished to do so, subject to
18 // the following conditions:
19 // 
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
22 // 
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 //
31 using System;
32 using System.Collections;
33 using System.Globalization;
34 using System.Reflection;
35 using System.Text;
36 using System.Xml;
37 using System.Xml.XPath;
38 using System.Xml.Xsl;
39 using Mono.Xml.Xsl;
40
41 using QName = System.Xml.XmlQualifiedName;
42
43 namespace Mono.Xml.Xsl
44 {
45         internal abstract class XPFuncImpl : IXsltContextFunction 
46         {
47                 int minargs, maxargs;
48                 XPathResultType returnType;
49                 XPathResultType [] argTypes;
50
51                 public XPFuncImpl () {}
52                 public XPFuncImpl (int minArgs, int maxArgs, XPathResultType returnType, XPathResultType[] argTypes)
53                 {
54                         this.Init(minArgs, maxArgs, returnType, argTypes);
55                 }
56                 
57                 protected void Init (int minArgs, int maxArgs, XPathResultType returnType, XPathResultType[] argTypes)
58                 {
59                         this.minargs    = minArgs;
60                         this.maxargs    = maxArgs;
61                         this.returnType = returnType;
62                         this.argTypes   = argTypes;
63                 }
64
65                 public int Minargs { get { return this.minargs; }}
66                 public int Maxargs { get { return this.maxargs; }}
67                 public XPathResultType ReturnType { get { return this.returnType; }}
68                 public XPathResultType [] ArgTypes { get { return this.argTypes; }}
69                 public object Invoke (XsltContext xsltContext, object [] args, XPathNavigator docContext)
70                 {
71                         return Invoke ((XsltCompiledContext)xsltContext, args, docContext);
72                 }
73                 
74                 public abstract object Invoke (XsltCompiledContext xsltContext, object [] args, XPathNavigator docContext);
75                 
76                 public static XPathResultType GetXPathType (Type type, XPathNavigator node) {
77                         switch (Type.GetTypeCode(type)) {
78                         case TypeCode.String:
79                                 return XPathResultType.String;
80                         case TypeCode.Boolean:
81                                 return XPathResultType.Boolean;
82                         case TypeCode.Object:
83                                 if (typeof (XPathNavigator).IsAssignableFrom (type) || typeof (IXPathNavigable).IsAssignableFrom (type))
84                                         return XPathResultType.Navigator;
85                                 
86                                 if (typeof (XPathNodeIterator).IsAssignableFrom (type))
87                                         return XPathResultType.NodeSet;
88                                 
89                                 return XPathResultType.Any;
90                         case TypeCode.DateTime :
91                                 throw new XsltException ("Invalid type DateTime was specified.", null, node);
92                         default: // Numeric
93                                 return XPathResultType.Number;
94                         } 
95                 }
96         }
97         
98         class XsltExtensionFunction : XPFuncImpl 
99         {
100                 private object extension;
101                 private MethodInfo method;
102                 private TypeCode [] typeCodes;
103
104                 public XsltExtensionFunction (object extension, MethodInfo method, XPathNavigator currentNode)
105                 {
106                         this.extension = extension;
107                         this.method = method;
108
109                         ParameterInfo [] parameters = method.GetParameters ();
110                         int minArgs = parameters.Length;
111                         int maxArgs = parameters.Length;
112                         
113                         this.typeCodes = new TypeCode [parameters.Length];
114                         XPathResultType[] argTypes = new XPathResultType [parameters.Length];
115                         
116                         bool canBeOpt = true;
117                         for (int i = parameters.Length - 1; 0 <= i; i--) { // optionals at the end
118                                 typeCodes [i] = Type.GetTypeCode (parameters [i].ParameterType);
119                                 argTypes [i] = GetXPathType (parameters [i].ParameterType, currentNode);
120                                 if (canBeOpt) {
121                                         if (parameters[i].IsOptional)
122                                                 minArgs --;
123                                         else
124                                                 canBeOpt = false;
125                                 }
126                         }
127                         base.Init (minArgs, maxArgs, GetXPathType (method.ReturnType, currentNode), argTypes);
128                 }
129
130                 public override object Invoke (XsltCompiledContext xsltContext, object [] args, XPathNavigator docContext)
131                 {
132                         try {
133                                 ParameterInfo [] pis = method.GetParameters ();
134                                 object [] castedArgs = new object [pis.Length];
135                                 for (int i = 0; i < args.Length; i++) {
136                                         Type t = pis [i].ParameterType;
137                                         switch (t.FullName) {
138                                         case "System.Int16":
139                                         case "System.UInt16":
140                                         case "System.Int32":
141                                         case "System.UInt32":
142                                         case "System.Int64":
143                                         case "System.UInt64":
144                                         case "System.Single":
145                                         case "System.Decimal":
146                                                 castedArgs [i] = Convert.ChangeType (args [i], t);
147                                                 break;
148                                         default:
149                                                 castedArgs [i] = args [i];
150                                                 break;
151                                         }
152                                 }
153
154                                 object result = null;
155                                 switch (method.ReturnType.FullName) {
156                                 case "System.Int16":
157                                 case "System.UInt16":
158                                 case "System.Int32":
159                                 case "System.UInt32":
160                                 case "System.Int64":
161                                 case "System.UInt64":
162                                 case "System.Single":
163                                 case "System.Decimal":
164                                         result = Convert.ChangeType (method.Invoke (extension, castedArgs), typeof (double));
165                                         break;
166                                 default:
167                                         result = method.Invoke(extension, castedArgs);
168                                         break;
169                                 }
170                                 IXPathNavigable navigable = result as IXPathNavigable;
171                                 if (navigable != null)
172                                         return navigable.CreateNavigator ();
173
174                                 return result;
175                         } catch (Exception ex) {
176                                 throw new XsltException ("Custom function reported an error.", ex);
177 //                              Debug.WriteLine ("****** INCORRECT RESOLUTION **********");
178                         }
179                 }
180         }
181         
182         class XsltCurrent : XPathFunction 
183         {
184                 public XsltCurrent (FunctionArguments args) : base (args)
185                 {
186                         if (args != null)
187                                 throw new XPathException ("current takes 0 args");
188                 }
189                 
190                 public override XPathResultType ReturnType { get { return XPathResultType.NodeSet; }}
191
192                 public override object Evaluate (BaseIterator iter)
193                 {
194                         XsltCompiledContext ctx = (XsltCompiledContext) iter.NamespaceManager;
195                         return new SelfIterator ((ctx).Processor.CurrentNode, ctx);
196                 }
197
198                 internal override bool Peer {
199                         get { return false; }
200                 }
201
202                 public override string ToString ()
203                 {
204                         return "current()";
205                 }
206         }
207         
208         class XsltDocument : XPathFunction 
209         {
210                 Expression arg0, arg1;
211                 XPathNavigator doc;
212                 
213                 public XsltDocument (FunctionArguments args, Compiler c) : base (args)
214                 {
215                         if (args == null || (args.Tail != null && args.Tail.Tail != null))
216                                 throw new XPathException ("document takes one or two args");
217                         
218                         arg0 = args.Arg;
219                         if (args.Tail != null)
220                                 arg1 = args.Tail.Arg;
221                         doc = c.Input.Clone ();
222                 }
223                 public override XPathResultType ReturnType { get { return XPathResultType.NodeSet; }}
224
225                 internal override bool Peer {
226                         get { return arg0.Peer && (arg1 != null ? arg1.Peer : true); }
227                 }
228
229                 public override object Evaluate (BaseIterator iter)
230                 {
231                         string baseUri = null;
232                         if (arg1 != null) {
233                                 XPathNodeIterator it = arg1.EvaluateNodeSet (iter);
234                                 if (it.MoveNext())
235                                         baseUri = it.Current.BaseURI;
236                                 else
237                                         baseUri = VoidBaseUriFlag;
238                         }
239
240                         object o = arg0.Evaluate (iter);
241                         if (o is XPathNodeIterator)
242                                 return GetDocument ((iter.NamespaceManager as XsltCompiledContext), (XPathNodeIterator)o, baseUri);
243                         else
244                                 return GetDocument ((iter.NamespaceManager as XsltCompiledContext), o is IFormattable ? ((IFormattable) o).ToString (null, CultureInfo.InvariantCulture) : o.ToString (), baseUri);
245                 }
246                 
247                 static string VoidBaseUriFlag = "&^)(*&%*^$&$VOID!BASE!URI!";
248                 
249                 Uri Resolve (string thisUri, string baseUri, XslTransformProcessor p)
250                 {
251 //                      Debug.WriteLine ("THIS: " + thisUri);
252 //                      Debug.WriteLine ("BASE: " + baseUri);
253                         XmlResolver r = p.Resolver;
254                         if (r == null)
255                                 return null;
256                         Uri uriBase = null;
257                         if (! object.ReferenceEquals (baseUri, VoidBaseUriFlag) && baseUri != String.Empty)
258                                 uriBase = r.ResolveUri (null, baseUri);
259                                 
260                         return r.ResolveUri (uriBase, thisUri);
261                 }
262                 
263                 XPathNodeIterator GetDocument (XsltCompiledContext xsltContext, XPathNodeIterator itr, string baseUri)
264                 {
265                         ArrayList list = new ArrayList ();
266                         try {
267                                 Hashtable got = new Hashtable ();
268                         
269                                 while (itr.MoveNext()) {
270                                         Uri uri = Resolve (itr.Current.Value, baseUri != null ? baseUri : /*itr.Current.BaseURI*/doc.BaseURI, xsltContext.Processor);
271                                         if (!got.ContainsKey (uri)) {
272                                                 got.Add (uri, null);
273                                                 if (uri != null && uri.ToString () == "") {
274                                                         XPathNavigator n = doc.Clone ();
275                                                         n.MoveToRoot ();
276                                                         list.Add (n);
277                                                 } else
278                                                         list.Add (xsltContext.Processor.GetDocument (uri));
279                                         }
280                                 }
281                         } catch (Exception) {
282                                 // Error recovery.
283                                 // See http://www.w3.org/TR/xslt#document and
284                                 // bug #75663.
285                                 list.Clear ();
286                         }
287                         return new ListIterator (list, xsltContext);
288                 }
289         
290                 XPathNodeIterator GetDocument (XsltCompiledContext xsltContext, string arg0, string baseUri)
291                 {
292                         try {
293                                 Uri uri = Resolve (arg0, baseUri != null ? baseUri : doc.BaseURI, xsltContext.Processor);
294                                 XPathNavigator n;
295                                 if (uri != null && uri.ToString () == "") {
296                                         n = doc.Clone ();
297                                         n.MoveToRoot ();
298                                 } else
299                                         n = xsltContext.Processor.GetDocument (uri);
300                         
301                                 return new SelfIterator (n, xsltContext);
302                         } catch (Exception) {
303                                 return new ListIterator (new ArrayList (), xsltContext);
304                         }
305                 }
306
307                 public override string ToString ()
308                 {
309                         return String.Concat ("document(",
310                                 arg0.ToString (),
311                                 arg1 != null ? "," : String.Empty,
312                                 arg1 != null ? arg1.ToString () : String.Empty,
313                                 ")");
314                 }
315         }
316         
317         class XsltElementAvailable : XPathFunction 
318         {
319                 Expression arg0;
320                 IStaticXsltContext ctx;
321                 
322                 public XsltElementAvailable (FunctionArguments args, IStaticXsltContext ctx) : base (args)
323                 {
324                         if (args == null || args.Tail != null)
325                                 throw new XPathException ("element-available takes 1 arg");
326                         
327                         arg0 = args.Arg;
328                         this.ctx = ctx;
329                 }
330                 
331                 public override XPathResultType ReturnType { get { return XPathResultType.Boolean; }}
332
333                 internal override bool Peer {
334                         get { return arg0.Peer; }
335                 }
336
337                 public override object Evaluate (BaseIterator iter)
338                 {
339                         QName name = XslNameUtil.FromString (arg0.EvaluateString (iter), ctx);
340
341                         return (
342                                 (name.Namespace == Compiler.XsltNamespace) &&
343                                 (
344                                         //
345                                         // A list of all the instructions (does not include top-level-elements)
346                                         //
347                                         name.Name == "apply-imports" ||
348                                         name.Name == "apply-templates" ||
349                                         name.Name == "call-template" ||
350                                         name.Name == "choose" ||
351                                         name.Name == "comment" ||
352                                         name.Name == "copy" ||
353                                         name.Name == "copy-of" ||
354                                         name.Name == "element" ||
355                                         name.Name == "fallback" ||
356                                         name.Name == "for-each" ||
357                                         name.Name == "message" ||
358                                         name.Name == "number" ||
359                                         name.Name == "processing-instruction" ||
360                                         name.Name == "text" ||
361                                         name.Name == "value-of" ||
362                                         name.Name == "variable"
363                                 )
364                         );
365                 }
366         }
367
368         class XsltFormatNumber : XPathFunction 
369         {
370                 Expression arg0, arg1, arg2;
371                 IStaticXsltContext ctx;
372                 
373                 public XsltFormatNumber (FunctionArguments args, IStaticXsltContext ctx) : base (args)
374                 {
375                         if (args == null || args.Tail == null || (args.Tail.Tail != null && args.Tail.Tail.Tail != null))
376                                 throw new XPathException ("format-number takes 2 or 3 args");
377                         
378                         arg0 = args.Arg;
379                         arg1 = args.Tail.Arg;
380                         if (args.Tail.Tail != null) {
381                                 arg2= args.Tail.Tail.Arg;
382                                 this.ctx = ctx;
383                         }
384                 }
385                 public override XPathResultType ReturnType { get { return XPathResultType.String; }}
386
387                 internal override bool Peer {
388                         get { return arg0.Peer && arg1.Peer && (arg2 != null ? arg2.Peer : true); }
389                 }
390                 
391                 public override object Evaluate (BaseIterator iter)
392                 {
393                         double d = arg0.EvaluateNumber (iter);
394                         string s = arg1.EvaluateString (iter);
395                         QName nm = QName.Empty;
396                         
397                         if (arg2 != null)
398                                 nm = XslNameUtil.FromString (arg2.EvaluateString (iter), ctx);
399                         
400                         try {
401                                 return ((XsltCompiledContext) iter.NamespaceManager).Processor.CompiledStyle
402                                 .LookupDecimalFormat (nm).FormatNumber (d, s);
403                         } catch (ArgumentException ex) {
404                                 throw new XsltException (ex.Message, ex, iter.Current);
405                         }
406                 }
407         }
408         
409         class XsltFunctionAvailable : XPathFunction 
410         {
411                 Expression arg0;
412                 IStaticXsltContext ctx;
413                 
414                 public XsltFunctionAvailable (FunctionArguments args, IStaticXsltContext ctx) : base (args)
415                 {
416                         if (args == null || args.Tail != null)
417                                 throw new XPathException ("element-available takes 1 arg");
418                         
419                         arg0 = args.Arg;
420                         this.ctx = ctx;
421                 }
422                 
423                 public override XPathResultType ReturnType { get { return XPathResultType.Boolean; }}
424
425                 internal override bool Peer {
426                         get { return arg0.Peer; }
427                 }
428                 
429                 public override object Evaluate (BaseIterator iter)
430                 {
431                         
432                         string name = arg0.EvaluateString (iter);
433                         int colon = name.IndexOf (':');
434                         // extension function
435                         if (colon > 0)
436                                 return (iter.NamespaceManager as XsltCompiledContext).ResolveFunction (
437                                         XslNameUtil.FromString (name, ctx),
438                                         null) != null;
439                         
440                         return (
441                                 //
442                                 // XPath
443                                 //
444                                 name == "boolean" ||
445                                 name == "ceiling" ||
446                                 name == "concat" ||
447                                 name == "contains" ||
448                                 name == "count" ||
449                                 name == "false" ||
450                                 name == "floor" ||
451                                 name == "id"||
452                                 name == "lang" ||
453                                 name == "last" ||
454                                 name == "local-name" ||
455                                 name == "name" ||
456                                 name == "namespace-uri" ||
457                                 name == "normalize-space" ||
458                                 name == "not" ||
459                                 name == "number" ||
460                                 name == "position" ||
461                                 name == "round" ||
462                                 name == "starts-with" ||
463                                 name == "string" ||
464                                 name == "string-length" ||
465                                 name == "substring" ||
466                                 name == "substring-after" ||
467                                 name == "substring-before" ||
468                                 name == "sum" ||
469                                 name == "translate" ||
470                                 name == "true" ||
471                                 // XSLT
472                                 name == "document" ||
473                                 name == "format-number" ||
474                                 name == "function-available" ||
475                                 name == "generate-id" ||
476                                 name == "key" ||
477                                 name == "current" ||
478                                 name == "unparsed-entity-uri" ||
479                                 name == "element-available" ||
480                                 name == "system-property"
481                         );
482                 }
483         } 
484
485         class XsltGenerateId : XPathFunction 
486         {
487                 //FIXME: generate short string, not the huge thing it makes now
488                 Expression arg0;
489                 public XsltGenerateId (FunctionArguments args) : base (args)
490                 {
491                         if (args != null) {
492                                 if (args.Tail != null)
493                                         throw new XPathException ("generate-id takes 1 or no args");
494                                 arg0 = args.Arg;
495                         }
496                 }
497                 
498                 public override XPathResultType ReturnType { get { return XPathResultType.String; }}
499
500                 internal override bool Peer {
501                         get { return arg0.Peer; }
502                 }
503
504                 public override object Evaluate (BaseIterator iter)
505                 {
506                         XPathNavigator n;
507                         if (arg0 != null) {
508                                 XPathNodeIterator itr = arg0.EvaluateNodeSet (iter);
509                                 if (itr.MoveNext ())
510                                         n = itr.Current.Clone ();
511                                 else
512                                         return string.Empty; // empty nodeset == empty string
513                         } else
514                                 n = iter.Current.Clone ();
515                         
516                         StringBuilder sb = new StringBuilder ("Mono"); // Ensure begins with alpha
517                         sb.Append (XmlConvert.EncodeLocalName (n.BaseURI));
518                         sb.Replace ('_', 'm'); // remove underscores from EncodeLocalName
519                         sb.Append (n.NodeType);
520                         sb.Append ('m');
521
522                         do {
523                                 sb.Append (IndexInParent (n));
524                                 sb.Append ('m');
525                         } while (n.MoveToParent ());
526                         
527                         return sb.ToString ();
528                 }
529                 
530                 int IndexInParent (XPathNavigator nav)
531                 {
532                         int n = 0;
533                         while (nav.MoveToPrevious ())
534                                 n++;
535                         
536                         return n;
537                 }
538         } 
539         
540         class XsltKey : XPathFunction 
541         {
542                 Expression arg0, arg1;
543                 IStaticXsltContext staticContext;
544                 
545                 public XsltKey (FunctionArguments args, IStaticXsltContext ctx) : base (args)
546                 {
547                         staticContext = ctx;
548                         if (args == null || args.Tail == null)
549                                 throw new XPathException ("key takes 2 args");
550                         arg0 = args.Arg;
551                         arg1 = args.Tail.Arg;
552                 }
553                 public Expression KeyName { get { return arg0; } }
554                 public Expression Field { get { return arg1; } }
555                 public override XPathResultType ReturnType { get { return XPathResultType.NodeSet; }}
556
557                 internal override bool Peer {
558                         get { return arg0.Peer && arg1.Peer; }
559                 }
560
561                 public bool PatternMatches (XPathNavigator nav, XsltContext nsmgr)
562                 {
563                         XsltCompiledContext ctx = nsmgr as XsltCompiledContext;
564                         // for key pattern, it must contain literal value
565                         return ctx.MatchesKey (nav, staticContext,
566                                 arg0.StaticValueAsString,
567                                 arg1.StaticValueAsString);
568                 }
569
570                 public override object Evaluate (BaseIterator iter)
571                 {
572                         XsltCompiledContext ctx = iter.NamespaceManager
573                                 as XsltCompiledContext;
574                         return ctx.EvaluateKey (staticContext, iter, arg0, arg1);
575                 }
576         }
577         
578         class XsltSystemProperty : XPathFunction 
579         {
580                 Expression arg0;
581                 IStaticXsltContext ctx;
582                 
583                 public XsltSystemProperty (FunctionArguments args, IStaticXsltContext ctx) : base (args)
584                 {
585                         if (args == null || args.Tail != null)
586                                 throw new XPathException ("system-property takes 1 arg");
587                         
588                         arg0 = args.Arg;
589                         this.ctx = ctx;
590                 }
591                 
592                 public override XPathResultType ReturnType { get { return XPathResultType.String; }}
593
594                 internal override bool Peer {
595                         get { return arg0.Peer; }
596                 }
597
598                 public override object Evaluate (BaseIterator iter)
599                 {
600                         QName name = XslNameUtil.FromString (arg0.EvaluateString (iter), ctx);
601                         
602                         if (name.Namespace == Compiler.XsltNamespace) {
603                                 switch (name.Name) {
604                                         case "version": return "1.0";
605                                         case "vendor": return "Mono";
606                                         case "vendor-url": return "http://www.go-mono.com/";
607                                 }
608                         }
609                         
610                         return "";
611                 }
612         } 
613
614         class XsltUnparsedEntityUri : XPathFunction 
615         {
616                 Expression arg0;
617                 
618                 public XsltUnparsedEntityUri (FunctionArguments args) : base (args)
619                 {
620                         if (args == null || args.Tail != null)
621                                 throw new XPathException ("unparsed-entity-uri takes 1 arg");
622                         
623                         arg0 = args.Arg;
624                 }
625                 
626                 public override XPathResultType ReturnType { get { return XPathResultType.String; }}
627
628                 internal override bool Peer {
629                         get { return arg0.Peer; }
630                 }
631
632                 public override object Evaluate (BaseIterator iter)
633                 {
634                         IHasXmlNode xn = iter.Current as IHasXmlNode;
635                         if (xn == null)
636                                 return String.Empty;
637                         XmlNode n = xn.GetNode ();
638                         if (n.OwnerDocument == null)
639                                 return String.Empty;
640                         XmlDocumentType doctype = n.OwnerDocument.DocumentType;
641                         if (doctype == null)
642                                 return String.Empty;
643                         XmlEntity ent = doctype.Entities.GetNamedItem (arg0.EvaluateString (iter)) as XmlEntity;
644                         if (ent == null)
645                                 return String.Empty;
646                         return ent.SystemId != null ? ent.SystemId : String.Empty;
647                 }
648         }
649
650         class MSXslNodeSet : XPathFunction
651         {
652                 Expression arg0;
653
654                 public MSXslNodeSet (FunctionArguments args) : base (args)
655                 {
656                         if (args == null || args.Tail != null)
657                                 throw new XPathException ("element-available takes 1 arg");
658                         
659                         arg0 = args.Arg;
660                 }
661
662                 public override XPathResultType ReturnType {
663                         get {
664                                 return XPathResultType.NodeSet;
665                         }
666                 }
667
668                 internal override bool Peer {
669                         get { return arg0.Peer; }
670                 }
671
672                 public override object Evaluate (BaseIterator iter)
673                 {
674                         XsltCompiledContext ctx = iter.NamespaceManager as XsltCompiledContext;
675                         XPathNavigator loc = iter.Current != null ? iter.Current.Clone () : null;
676                         XPathNavigator nav = arg0.EvaluateAs (iter, XPathResultType.Navigator) as XPathNavigator;
677                         if (nav == null) {
678                                 if (loc != null)
679                                         return new XsltException ("Cannot convert the XPath argument to a result tree fragment.", null, loc);
680                                 else
681                                         return new XsltException ("Cannot convert the XPath argument to a result tree fragment.", null);
682                         }
683                         ArrayList al = new ArrayList ();
684                         al.Add (nav);
685                         return new ListIterator (al, ctx);
686                 }
687         }
688 }