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