//
// (C) 2002 Piers Haken
//
+
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
using System;
using System.Collections;
+using System.Globalization;
using System.Xml;
using System.Xml.XPath;
using System.Xml.Xsl;
+using System.Text;
namespace System.Xml.XPath
{
- /// <summary>
- /// Summary description for DefaultContext.
- /// </summary>
- internal class DefaultContext : XsltContext
- {
- protected static Hashtable _htFunctions = new Hashtable ();
-
- static DefaultContext()
- {
- Add (new XPathFunctionLast ());
- Add (new XPathFunctionPosition ());
- Add (new XPathFunctionCount ());
- Add (new XPathFunctionId ());
- Add (new XPathFunctionLocalName ());
- Add (new XPathFunctionNamespaceUri ());
- Add (new XPathFunctionName ());
- Add (new XPathFunctionString ());
- Add (new XPathFunctionConcat ());
- Add (new XPathFunctionStartsWith ());
- Add (new XPathFunctionContains ());
- Add (new XPathFunctionSubstringBefore ());
- Add (new XPathFunctionSubstringAfter ());
- Add (new XPathFunctionSubstring ());
- Add (new XPathFunctionStringLength ());
- Add (new XPathFunctionNormalizeSpace ());
- Add (new XPathFunctionTranslate ());
- Add (new XPathFunctionBoolean ());
- Add (new XPathFunctionNot ());
- Add (new XPathFunctionTrue ());
- Add (new XPathFunctionFalse ());
- Add (new XPathFunctionLang ());
- Add (new XPathFunctionNumber ());
- Add (new XPathFunctionSum ());
- Add (new XPathFunctionFloor ());
- Add (new XPathFunctionCeil ());
- Add (new XPathFunctionRound ());
- }
-
- [MonoTODO]
- public override IXsltContextFunction ResolveFunction (string prefix, string name, XPathResultType[] ArgTypes)
- {
- // match the prefix
- if (prefix != null && prefix != "") // TODO: should we allow some namespaces here?
- return null;
-
- // match the function name
- XPathFunction fn = (XPathFunction) _htFunctions [name];
- if (fn == null)
- return null;
-
- // check the number of arguments
- int cArgs = ArgTypes.Length;
- if (cArgs < fn.Minargs || cArgs > fn.Maxargs)
- return null;
-
- // check the types of the arguments
- XPathResultType [] rgTypes = fn.ArgTypes;
- if (rgTypes == null)
- {
- if (cArgs != 0)
- return null;
- }
- else
- {
- int cTypes = rgTypes.Length;
- for (int iArg = 0; iArg < cArgs; iArg ++)
- {
- XPathResultType typeRequested = ArgTypes [iArg];
- XPathResultType typeDefined = (iArg >= cTypes) ? rgTypes [cTypes - 1] : rgTypes [iArg];
- if (typeDefined != XPathResultType.Any && typeDefined != typeRequested)
- return null;
- }
- }
- return fn;
- }
- public override IXsltContextVariable ResolveVariable (string prefix, string name)
- {
- return null;
- }
- [MonoTODO]
- public override int CompareDocument (string baseUri, string nextBaseUri) { throw new NotImplementedException (); }
- [MonoTODO]
- public override bool PreserveWhitespace (XPathNavigator nav) { throw new NotImplementedException (); }
- [MonoTODO]
- public override bool Whitespace { get { throw new NotImplementedException (); }}
- protected static void Add (XPathFunction fn)
- {
- _htFunctions.Add (fn.Name, fn);
- }
- }
-
internal class XPathFunctions
{
public static bool ToBoolean (object arg)
BaseIterator iter = (BaseIterator) arg;
return iter.MoveNext ();
}
+ if (arg is XPathNavigator)
+ {
+ return ToBoolean (((XPathNavigator) arg).SelectChildren (XPathNodeType.All));
+ }
throw new ArgumentException ();
}
- [MonoTODO]
+
+ public static bool ToBoolean (bool b)
+ {
+ return b;
+ }
+
+ public static bool ToBoolean (double d)
+ {
+ return d != 0.0 && d != double.NaN;
+ }
+
+ public static bool ToBoolean (string s)
+ {
+ return s != null && s.Length > 0;
+ }
+
+ public static bool ToBoolean (BaseIterator iter)
+ {
+ return iter != null && iter.MoveNext ();
+ }
+
public static string ToString (object arg)
{
if (arg == null)
if (arg is bool)
return ((bool) arg) ? "true" : "false";
if (arg is double)
- return ((double) arg).ToString ("R", System.Globalization.NumberFormatInfo.InvariantInfo);
+ return ToString ((double) arg);
if (arg is BaseIterator)
{
BaseIterator iter = (BaseIterator) arg;
return "";
return iter.Current.Value;
}
+ if (arg is XPathNavigator)
+ {
+ return ((XPathNavigator) arg).Value;
+ }
throw new ArgumentException ();
}
- [MonoTODO]
+
+ public static string ToString (double d)
+ {
+ // See XPath 1.0 section 4.2
+ if (d == Double.NegativeInfinity)
+ return "-Infinity";
+ if (d == Double.PositiveInfinity)
+ return "Infinity";
+ // FIXME:
+ // Return string in roundtrip format (currently it
+ // rather breaks things, so we don't use it until
+ // System.Double gets fixed.)
+#if TARGET_JVM
+ return d.ToString ("R", System.Globalization.NumberFormatInfo.InvariantInfo);
+#else
+ return ((double) d).ToString (System.Globalization.NumberFormatInfo.InvariantInfo);
+#endif
+ }
+
public static double ToNumber (object arg)
{
if (arg == null)
throw new ArgumentNullException ();
- if (arg is BaseIterator)
+ if (arg is BaseIterator || arg is XPathNavigator)
arg = ToString (arg); // follow on
- if (arg is string)
- return XmlConvert.ToDouble ((string) arg); // TODO: spec? convert string to number
+ if (arg is string) {
+ string s = arg as string;
+ return ToNumber (s); // use explicit overload
+ }
if (arg is double)
return (double) arg;
if (arg is bool)
return Convert.ToDouble ((bool) arg);
throw new ArgumentException ();
}
- }
-
- internal abstract class XPathFunction : IXsltContextFunction
- {
- public abstract XPathResultType ReturnType { get; }
- public abstract int Minargs { get; }
- public abstract int Maxargs { get; }
- public abstract XPathResultType [] ArgTypes { get; }
- public object Invoke (XsltContext xsltContext, object[] args, XPathNavigator docContext)
+
+ public static double ToNumber (string arg)
{
- return TypesafeInvoke (xsltContext, args, docContext);
+ if (arg == null)
+ throw new ArgumentNullException ();
+ string s = arg.Trim (XmlChar.WhitespaceChars);
+ if (s.Length == 0)
+ return double.NaN;
+ try {
+ return XmlConvert.ToDouble (s);
+ } catch (System.OverflowException) {
+ return double.NaN;
+ } catch (System.FormatException) {
+ return double.NaN;
+ }
}
+ }
- public abstract string Name { get; }
- public abstract object TypesafeInvoke (XsltContext xsltContext, object[] args, XPathNavigator docContext);
+ internal abstract class XPathFunction : Expression
+ {
+ public XPathFunction (FunctionArguments args) {}
}
+
internal class XPathFunctionLast : XPathFunction
{
+ public XPathFunctionLast (FunctionArguments args) : base (args)
+ {
+ if (args != null)
+ throw new XPathException ("last takes 0 args");
+ }
+
public override XPathResultType ReturnType { get { return XPathResultType.Number; }}
- public override int Minargs { get { return 0; }}
- public override int Maxargs { get { return 0; }}
- public override XPathResultType [] ArgTypes { get { return null; }}
- public override object TypesafeInvoke (XsltContext xsltContext, object[] args, XPathNavigator docContext)
+
+ internal override bool Peer {
+ get { return true; }
+ }
+
+ public override object Evaluate (BaseIterator iter)
{
- throw new NotImplementedException (); // special-cased
+ return (double) iter.Count;
+ }
+
+ public override string ToString ()
+ {
+ return "last()";
+ }
+
+ internal override bool IsPositional {
+ get { return true; }
}
- public override string Name { get { return "last"; }}
}
+
+
internal class XPathFunctionPosition : XPathFunction
{
+ public XPathFunctionPosition (FunctionArguments args) : base (args)
+ {
+ if (args != null)
+ throw new XPathException ("position takes 0 args");
+ }
+
public override XPathResultType ReturnType { get { return XPathResultType.Number; }}
- public override int Minargs { get { return 0; }}
- public override int Maxargs { get { return 0; }}
- public override XPathResultType [] ArgTypes { get { return null; }}
- public override object TypesafeInvoke (XsltContext xsltContext, object[] args, XPathNavigator docContext)
+
+ internal override bool Peer {
+ get { return true; }
+ }
+
+ public override object Evaluate (BaseIterator iter)
{
- throw new NotImplementedException (); // special-cased
+ return (double) iter.CurrentPosition;
+ }
+
+ public override string ToString ()
+ {
+ return "position()";
+ }
+
+ internal override bool IsPositional {
+ get { return true; }
}
- public override string Name { get { return "position"; }}
}
+
+
internal class XPathFunctionCount : XPathFunction
{
+ Expression arg0;
+
+ public XPathFunctionCount (FunctionArguments args) : base (args)
+ {
+ if (args == null || args.Tail != null)
+ throw new XPathException ("count takes 1 arg");
+
+ arg0 = args.Arg;
+ }
+
public override XPathResultType ReturnType { get { return XPathResultType.Number; }}
- public override int Minargs { get { return 1; }}
- public override int Maxargs { get { return 1; }}
- public override XPathResultType [] ArgTypes { get { return new XPathResultType [] { XPathResultType.NodeSet }; }}
- public override object TypesafeInvoke (XsltContext xsltContext, object[] args, XPathNavigator docContext)
+
+ internal override bool Peer {
+ get { return arg0.Peer; }
+ }
+
+ public override object Evaluate (BaseIterator iter)
+ {
+ return (double) arg0.EvaluateNodeSet (iter).Count;
+ }
+
+ public override bool EvaluateBoolean (BaseIterator iter)
+ {
+ if (arg0.GetReturnType (iter) == XPathResultType.NodeSet)
+ return arg0.EvaluateBoolean (iter);
+
+ return arg0.EvaluateNodeSet (iter).MoveNext ();
+ }
+
+ public override string ToString ()
{
- return ((BaseIterator) args [0]).Count;
+ return "count(" + arg0.ToString () + ")";
}
- public override string Name { get { return "count"; }}
}
+
+
internal class XPathFunctionId : XPathFunction
{
+ Expression arg0;
+
+ public XPathFunctionId (FunctionArguments args) : base (args)
+ {
+ if (args == null || args.Tail != null)
+ throw new XPathException ("id takes 1 arg");
+
+ arg0 = args.Arg;
+ }
+
+ public Expression Id { get { return arg0; } }
+
private static char [] rgchWhitespace = {' ', '\t', '\r', '\n'};
public override XPathResultType ReturnType { get { return XPathResultType.NodeSet; }}
- public override int Minargs { get { return 1; }}
- public override int Maxargs { get { return 1; }}
- public override XPathResultType [] ArgTypes { get { return new XPathResultType [] { XPathResultType.Any }; }}
- [MonoTODO]
- public override object TypesafeInvoke (XsltContext xsltContext, object[] args, XPathNavigator docContext)
+
+ internal override bool Peer {
+ get { return arg0.Peer; }
+ }
+
+ public override object Evaluate (BaseIterator iter)
{
String strArgs;
- BaseIterator iter = args [0] as BaseIterator;
- if (iter != null)
+ object val = arg0.Evaluate (iter);
+
+ BaseIterator valItr = val as BaseIterator;
+ if (valItr != null)
{
strArgs = "";
- while (!iter.MoveNext ())
- strArgs += iter.Current.Value + " ";
+ while (valItr.MoveNext ())
+ strArgs += valItr.Current.Value + " ";
}
else
- strArgs = XPathFunctions.ToString (args [0]);
- string [] rgstrArgs = strArgs.Split (rgchWhitespace);
+ strArgs = XPathFunctions.ToString (val);
+
+ XPathNavigator n = iter.Current.Clone ();
ArrayList rgNodes = new ArrayList ();
- foreach (string strArg in rgstrArgs)
- {
- if (docContext.MoveToId (strArg))
- rgNodes.Add (docContext.Clone ());
- }
- return new ArrayListIterator (iter, rgNodes);
+ string [] ids = strArgs.Split (rgchWhitespace);
+ for (int i = 0; i < ids.Length; i++)
+ if (n.MoveToId (ids [i]))
+ rgNodes.Add (n.Clone ());
+
+ rgNodes.Sort (XPathNavigatorComparer.Instance);
+ return new ListIterator (iter, rgNodes);
+ }
+
+ public override string ToString ()
+ {
+ return "id(" + arg0.ToString () + ")";
}
- public override string Name { get { return "id"; }}
}
+
internal class XPathFunctionLocalName : XPathFunction
{
- public override XPathResultType ReturnType { get { return XPathResultType.NodeSet; }}
- public override int Minargs { get { return 0; }}
- public override int Maxargs { get { return 1; }}
- public override XPathResultType [] ArgTypes { get { return new XPathResultType [] { XPathResultType.NodeSet }; }}
- public override object TypesafeInvoke (XsltContext xsltContext, object[] args, XPathNavigator docContext)
+ Expression arg0;
+
+ public XPathFunctionLocalName (FunctionArguments args) : base (args)
{
- BaseIterator iter = (args.Length == 1) ? ((BaseIterator) args [0]) : new SelfIterator (docContext, xsltContext);
- if (iter == null || !iter.MoveNext ())
+ if (args != null) {
+ arg0 = args.Arg;
+ if (args.Tail != null)
+ throw new XPathException ("local-name takes 1 or zero args");
+ }
+ }
+
+ public override XPathResultType ReturnType { get { return XPathResultType.String; }}
+
+ internal override bool Peer {
+ get { return arg0 != null ? arg0.Peer : true; }
+ }
+
+ public override object Evaluate (BaseIterator iter)
+ {
+ if (arg0 == null)
+ return iter.Current.LocalName;
+
+ BaseIterator argNs = arg0.EvaluateNodeSet (iter);
+ if (argNs == null || !argNs.MoveNext ())
return "";
- return iter.Current.LocalName;
+ return argNs.Current.LocalName;
+ }
+
+ public override string ToString ()
+ {
+ return "local-name(" + arg0.ToString () + ")";
}
- public override string Name { get { return "local-name"; }}
}
+
+
internal class XPathFunctionNamespaceUri : XPathFunction
{
+ Expression arg0;
+
+ public XPathFunctionNamespaceUri (FunctionArguments args) : base (args)
+ {
+ if (args != null) {
+ arg0 = args.Arg;
+ if (args.Tail != null)
+ throw new XPathException ("namespace-uri takes 1 or zero args");
+ }
+ }
+
+ internal override bool Peer {
+ get { return arg0 != null ? arg0.Peer : true; }
+ }
+
public override XPathResultType ReturnType { get { return XPathResultType.String; }}
- public override int Minargs { get { return 0; }}
- public override int Maxargs { get { return 1; }}
- public override XPathResultType [] ArgTypes { get { return new XPathResultType [] { XPathResultType.NodeSet }; }}
- [MonoTODO]
- public override object TypesafeInvoke (XsltContext xsltContext, object[] args, XPathNavigator docContext)
- {
- BaseIterator iter = (args.Length == 1) ? ((BaseIterator) args [0]) : new SelfIterator (docContext, xsltContext);
- if (iter == null || !iter.MoveNext ())
+
+ public override object Evaluate (BaseIterator iter)
+ {
+ if (arg0 == null)
+ return iter.Current.NamespaceURI;
+
+ BaseIterator argNs = arg0.EvaluateNodeSet (iter);
+ if (argNs == null || !argNs.MoveNext ())
return "";
- return iter.Current.NamespaceURI; // TODO: should the namespace be expanded wrt. the given context?
+ return argNs.Current.NamespaceURI;
+ }
+
+ public override string ToString ()
+ {
+ return "namespace-uri(" + arg0.ToString () + ")";
}
- public override string Name { get { return "namespace-uri"; }}
}
+
+
internal class XPathFunctionName : XPathFunction
{
+ Expression arg0;
+
+ public XPathFunctionName (FunctionArguments args) : base (args)
+ {
+ if (args != null) {
+ arg0 = args.Arg;
+ if (args.Tail != null)
+ throw new XPathException ("name takes 1 or zero args");
+ }
+ }
+
public override XPathResultType ReturnType { get { return XPathResultType.String; }}
- public override int Minargs { get { return 0; }}
- public override int Maxargs { get { return 1; }}
- public override XPathResultType [] ArgTypes { get { return new XPathResultType [] { XPathResultType.NodeSet }; }}
- [MonoTODO]
- public override object TypesafeInvoke (XsltContext xsltContext, object[] args, XPathNavigator docContext)
- {
- BaseIterator iter = (args.Length == 1) ? ((BaseIterator) args [0]) : new SelfIterator (docContext, xsltContext);
- if (iter == null || !iter.MoveNext ())
+
+ internal override bool Peer {
+ get { return arg0 != null ? arg0.Peer : true; }
+ }
+
+ public override object Evaluate (BaseIterator iter)
+ {
+ if (arg0 == null)
+ return iter.Current.Name;
+
+ BaseIterator argNs = arg0.EvaluateNodeSet (iter);
+ if (argNs == null || !argNs.MoveNext ())
return "";
- return iter.Current.Name;
+ return argNs.Current.Name;
+ }
+
+ public override string ToString ()
+ {
+ return String.Concat ("name(",
+ arg0 != null ? arg0.ToString () : String.Empty,
+ ")");
}
- public override string Name { get { return "name"; }}
}
+
+
internal class XPathFunctionString : XPathFunction
{
+ Expression arg0;
+
+ public XPathFunctionString (FunctionArguments args) : base (args)
+ {
+ if (args != null) {
+ arg0 = args.Arg;
+ if (args.Tail != null)
+ throw new XPathException ("string takes 1 or zero args");
+ }
+ }
+
public override XPathResultType ReturnType { get { return XPathResultType.String; }}
- public override int Minargs { get { return 0; }}
- public override int Maxargs { get { return 1; }}
- public override XPathResultType [] ArgTypes { get { return new XPathResultType [] { XPathResultType.Any }; }}
- public override object TypesafeInvoke (XsltContext xsltContext, object[] args, XPathNavigator docContext)
+
+ internal override bool Peer {
+ get { return arg0 != null ? arg0.Peer : true; }
+ }
+
+ public override object Evaluate (BaseIterator iter)
{
- return XPathFunctions.ToString (args [0]);
+ if (arg0 == null)
+ return iter.Current.Value;
+ return arg0.EvaluateString (iter);
+ }
+
+ public override string ToString ()
+ {
+ return "string(" + arg0.ToString () + ")";
}
- public override string Name { get { return "string"; }}
}
+
+
internal class XPathFunctionConcat : XPathFunction
{
+ ArrayList rgs;
+
+ public XPathFunctionConcat (FunctionArguments args) : base (args)
+ {
+ if (args == null || args.Tail == null)
+ throw new XPathException ("concat takes 2 or more args");
+
+ args.ToArrayList (rgs = new ArrayList ());
+ }
+
public override XPathResultType ReturnType { get { return XPathResultType.String; }}
- public override int Minargs { get { return 2; }}
- public override int Maxargs { get { return int.MaxValue; }}
- public override XPathResultType [] ArgTypes { get { return new XPathResultType [] { XPathResultType.String, XPathResultType.String, XPathResultType.String }; }}
- public override object TypesafeInvoke (XsltContext xsltContext, object[] args, XPathNavigator docContext)
+
+ internal override bool Peer {
+ get {
+ for (int i = 0; i < rgs.Count; i++)
+ if (!((Expression) rgs [i]).Peer)
+ return false;
+ return true;
+ }
+ }
+
+ public override object Evaluate (BaseIterator iter)
+ {
+ StringBuilder sb = new StringBuilder ();
+
+ int len = rgs.Count;
+ for (int i = 0; i < len; i++)
+ sb.Append (((Expression)rgs[i]).EvaluateString (iter));
+
+ return sb.ToString ();
+ }
+
+ public override string ToString ()
{
- String str = "";
- foreach (string strArg in args)
- str += strArg;
- return str;
+ StringBuilder sb = new StringBuilder ();
+ sb.Append ("concat(");
+ for (int i = 0; i < rgs.Count - 1; i++) {
+ sb.AppendFormat (CultureInfo.InvariantCulture, "{0}", rgs [i].ToString ());
+ sb.Append (',');
+ }
+ sb.AppendFormat (CultureInfo.InvariantCulture, "{0}", rgs [rgs.Count - 1].ToString ());
+ sb.Append (')');
+ return sb.ToString ();
}
- public override string Name { get { return "concat"; }}
}
+
+
internal class XPathFunctionStartsWith : XPathFunction
{
+ Expression arg0, arg1;
+
+ public XPathFunctionStartsWith (FunctionArguments args) : base (args)
+ {
+ if (args == null || args.Tail == null || args.Tail.Tail != null)
+ throw new XPathException ("starts-with takes 2 args");
+
+ arg0 = args.Arg;
+ arg1 = args.Tail.Arg;
+ }
+
public override XPathResultType ReturnType { get { return XPathResultType.Boolean; }}
- public override int Minargs { get { return 2; }}
- public override int Maxargs { get { return 2; }}
- public override XPathResultType [] ArgTypes { get { return new XPathResultType [] { XPathResultType.String, XPathResultType.String }; }}
- public override object TypesafeInvoke (XsltContext xsltContext, object[] args, XPathNavigator docContext)
+
+ internal override bool Peer {
+ get { return arg0.Peer && arg1.Peer; }
+ }
+
+ public override object Evaluate (BaseIterator iter)
+ {
+ return arg0.EvaluateString (iter).StartsWith (arg1.EvaluateString (iter));
+ }
+
+ public override string ToString ()
{
- string str1 = (string) args [0];
- string str2 = (string) args [1];
- return str1.StartsWith (str2);
+ return String.Concat ("starts-with(", arg0.ToString (), ",", arg1.ToString (), ")");
}
- public override string Name { get { return "starts-with"; }}
}
+
+
internal class XPathFunctionContains : XPathFunction
{
+ Expression arg0, arg1;
+
+ public XPathFunctionContains (FunctionArguments args) : base (args)
+ {
+ if (args == null || args.Tail == null || args.Tail.Tail != null)
+ throw new XPathException ("contains takes 2 args");
+
+ arg0 = args.Arg;
+ arg1 = args.Tail.Arg;
+ }
+
public override XPathResultType ReturnType { get { return XPathResultType.Boolean; }}
- public override int Minargs { get { return 2; }}
- public override int Maxargs { get { return 2; }}
- public override XPathResultType [] ArgTypes { get { return new XPathResultType [] { XPathResultType.String, XPathResultType.String }; }}
- public override object TypesafeInvoke (XsltContext xsltContext, object[] args, XPathNavigator docContext)
+
+ internal override bool Peer {
+ get { return arg0.Peer && arg1.Peer; }
+ }
+
+ public override object Evaluate (BaseIterator iter)
+ {
+ return arg0.EvaluateString (iter).IndexOf (arg1.EvaluateString (iter)) != -1;
+ }
+
+ public override string ToString ()
{
- string str1 = (string) args [0];
- string str2 = (string) args [1];
- return str1.IndexOf (str2) != -1;
+ return String.Concat ("contains(", arg0.ToString (), ",", arg1.ToString (), ")");
}
- public override string Name { get { return "contains"; }}
}
+
+
internal class XPathFunctionSubstringBefore : XPathFunction
{
+ Expression arg0, arg1;
+
+ public XPathFunctionSubstringBefore (FunctionArguments args) : base (args)
+ {
+ if (args == null || args.Tail == null || args.Tail.Tail != null)
+ throw new XPathException ("substring-before takes 2 args");
+
+ arg0 = args.Arg;
+ arg1 = args.Tail.Arg;
+ }
+
public override XPathResultType ReturnType { get { return XPathResultType.String; }}
- public override int Minargs { get { return 2; }}
- public override int Maxargs { get { return 2; }}
- public override XPathResultType [] ArgTypes { get { return new XPathResultType [] { XPathResultType.String, XPathResultType.String }; }}
- public override object TypesafeInvoke (XsltContext xsltContext, object[] args, XPathNavigator docContext)
+
+ internal override bool Peer {
+ get { return arg0.Peer && arg1.Peer; }
+ }
+
+ public override object Evaluate (BaseIterator iter)
{
- string str1 = (string) args [0];
- string str2 = (string) args [1];
+ string str1 = arg0.EvaluateString (iter);
+ string str2 = arg1.EvaluateString (iter);
int ich = str1.IndexOf (str2);
if (ich <= 0)
return "";
return str1.Substring (0, ich);
}
- public override string Name { get { return "substring-before"; }}
+
+ public override string ToString ()
+ {
+ return String.Concat ("substring-before(", arg0.ToString (), ",", arg1.ToString (), ")");
+ }
}
+
+
internal class XPathFunctionSubstringAfter : XPathFunction
{
+ Expression arg0, arg1;
+
+ public XPathFunctionSubstringAfter (FunctionArguments args) : base (args)
+ {
+ if (args == null || args.Tail == null || args.Tail.Tail != null)
+ throw new XPathException ("substring-after takes 2 args");
+
+ arg0 = args.Arg;
+ arg1 = args.Tail.Arg;
+ }
+
public override XPathResultType ReturnType { get { return XPathResultType.String; }}
- public override int Minargs { get { return 2; }}
- public override int Maxargs { get { return 2; }}
- public override XPathResultType [] ArgTypes { get { return new XPathResultType [] { XPathResultType.String, XPathResultType.String }; }}
- public override object TypesafeInvoke (XsltContext xsltContext, object[] args, XPathNavigator docContext)
+
+ internal override bool Peer {
+ get { return arg0.Peer && arg1.Peer; }
+ }
+
+ public override object Evaluate (BaseIterator iter)
{
- string str1 = (string) args [0];
- string str2 = (string) args [1];
+ string str1 = arg0.EvaluateString (iter);
+ string str2 = arg1.EvaluateString (iter);
int ich = str1.IndexOf (str2);
- if (ich <= 0)
+ if (ich < 0)
return "";
return str1.Substring (ich + str2.Length);
}
- public override string Name { get { return "substring-after"; }}
+
+ public override string ToString ()
+ {
+ return String.Concat ("substring-after(", arg0.ToString (), ",", arg1.ToString (), ")");
+ }
}
+
+
internal class XPathFunctionSubstring : XPathFunction
{
+ Expression arg0, arg1, arg2;
+
+ public XPathFunctionSubstring (FunctionArguments args) : base (args)
+ {
+ if (args == null || args.Tail == null || (args.Tail.Tail != null && args.Tail.Tail.Tail != null))
+ throw new XPathException ("substring takes 2 or 3 args");
+
+ arg0 = args.Arg;
+ arg1 = args.Tail.Arg;
+ if (args.Tail.Tail != null)
+ arg2= args.Tail.Tail.Arg;
+ }
+
public override XPathResultType ReturnType { get { return XPathResultType.String; }}
- public override int Minargs { get { return 2; }}
- public override int Maxargs { get { return int.MaxValue; }}
- public override XPathResultType [] ArgTypes { get { return new XPathResultType [] { XPathResultType.String, XPathResultType.String, XPathResultType.String }; }}
- [MonoTODO]
- public override object TypesafeInvoke (XsltContext xsltContext, object[] args, XPathNavigator docContext)
- {
- // TODO: check this, what the hell were they smoking?
- string str = (string) args [0];
- double ich = Math.Round ((double) args [1]) - 1;
- if (Double.IsNaN (ich) || ich >= (double) str.Length)
+
+ internal override bool Peer {
+ get { return arg0.Peer && arg1.Peer && (arg2 != null ? arg2.Peer : true); }
+ }
+
+ public override object Evaluate (BaseIterator iter)
+ {
+ string str = arg0.EvaluateString (iter);
+ double ich = Math.Round (arg1.EvaluateNumber (iter)) - 1;
+ if (Double.IsNaN (ich) ||
+ Double.IsNegativeInfinity (ich) ||
+ ich >= (double) str.Length)
return "";
- if (args.Length == 2)
+ if (arg2 == null)
{
if (ich < 0)
ich = 0.0;
}
else
{
- double cch = Math.Round ((double) args [2]);
+ double cch = Math.Round (arg2.EvaluateNumber (iter));
if (Double.IsNaN (cch))
return "";
if (ich < 0.0 || cch < 0.0)
return str.Substring ((int) ich, (int) cch);
}
}
- public override string Name { get { return "substring"; }}
+
+ public override string ToString ()
+ {
+ return String.Concat (new string [] {
+ "substring(", arg0.ToString (), ",", arg1.ToString (), ",", arg2.ToString (), ")"});
+ }
}
+
+
internal class XPathFunctionStringLength : XPathFunction
{
+ Expression arg0;
+
+ public XPathFunctionStringLength (FunctionArguments args) : base (args)
+ {
+ if (args != null) {
+ arg0 = args.Arg;
+ if (args.Tail != null)
+ throw new XPathException ("string-length takes 1 or zero args");
+ }
+ }
+
public override XPathResultType ReturnType { get { return XPathResultType.Number; }}
- public override int Minargs { get { return 0; }}
- public override int Maxargs { get { return 1; }}
- public override XPathResultType [] ArgTypes { get { return new XPathResultType [] { XPathResultType.String }; }}
- public override object TypesafeInvoke (XsltContext xsltContext, object[] args, XPathNavigator docContext)
+
+ internal override bool Peer {
+ get { return arg0 != null ? arg0.Peer : true; }
+ }
+
+ public override object Evaluate (BaseIterator iter)
{
string str;
- if (args.Length == 1)
- str = (string) args [0];
+ if (arg0 != null)
+ str = arg0.EvaluateString (iter);
else
- str = docContext.Value;
+ str = iter.Current.Value;
return (double) str.Length;
}
- public override string Name { get { return "string-length"; }}
+
+ public override string ToString ()
+ {
+ return String.Concat (new string [] {
+ "string-length(", arg0.ToString (), ")"});
+ }
}
+
+
internal class XPathFunctionNormalizeSpace : XPathFunction
{
+ Expression arg0;
+
+ public XPathFunctionNormalizeSpace (FunctionArguments args) : base (args)
+ {
+ if (args != null) {
+ arg0 = args.Arg;
+ if (args.Tail != null)
+ throw new XPathException ("normalize-space takes 1 or zero args");
+ }
+ }
+
public override XPathResultType ReturnType { get { return XPathResultType.String; }}
- public override int Minargs { get { return 0; }}
- public override int Maxargs { get { return 1; }}
- public override XPathResultType [] ArgTypes { get { return new XPathResultType [] { XPathResultType.String }; }}
- [MonoTODO]
- public override object TypesafeInvoke (XsltContext xsltContext, object[] args, XPathNavigator docContext)
+
+ internal override bool Peer {
+ get { return arg0 !=null ? arg0.Peer : true; }
+ }
+
+ public override object Evaluate (BaseIterator iter)
{
string str;
- if (args.Length == 1)
- str = (string) args [0];
+ if (arg0 != null)
+ str = arg0.EvaluateString (iter);
else
- str = docContext.Value;
+ str = iter.Current.Value;
System.Text.StringBuilder sb = new System.Text.StringBuilder ();
bool fSpace = false;
- foreach (char ch in str)
- {
+ for (int i = 0; i < str.Length; i++) {
+ char ch = str [i];
if (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n')
{
fSpace = true;
}
return sb.ToString ();
}
- public override string Name { get { return "normalize-space"; }}
+
+ public override string ToString ()
+ {
+ return String.Concat (new string [] {
+ "normalize-space(",
+ arg0 != null ? arg0.ToString () : String.Empty,
+ ")"});
+ }
}
+
+
internal class XPathFunctionTranslate : XPathFunction
{
+ Expression arg0, arg1, arg2;
+
+ public XPathFunctionTranslate (FunctionArguments args) : base (args)
+ {
+ if (args == null || args.Tail == null || args.Tail.Tail == null || args.Tail.Tail.Tail != null)
+ throw new XPathException ("translate takes 3 args");
+
+ arg0 = args.Arg;
+ arg1 = args.Tail.Arg;
+ arg2= args.Tail.Tail.Arg;
+ }
+
public override XPathResultType ReturnType { get { return XPathResultType.String; }}
- public override int Minargs { get { return 3; }}
- public override int Maxargs { get { return 3; }}
- public override XPathResultType [] ArgTypes { get { return new XPathResultType [] { XPathResultType.String, XPathResultType.String, XPathResultType.String }; }}
- [MonoTODO]
- public override object TypesafeInvoke (XsltContext xsltContext, object[] args, XPathNavigator docContext)
+
+ internal override bool Peer {
+ get { return arg0.Peer && arg1.Peer && arg2.Peer; }
+ }
+
+ public override object Evaluate (BaseIterator iter)
+ {
+ string s0 = arg0.EvaluateString (iter);
+ string s1 = arg1.EvaluateString (iter);
+ string s2 = arg2.EvaluateString (iter);
+
+ StringBuilder ret = new StringBuilder (s0.Length);
+
+ int pos = 0, len = s0.Length, s2len = s2.Length;
+
+ while (pos < len) {
+ int idx = s1.IndexOf (s0 [pos]);
+
+ if (idx != -1) {
+ if (idx < s2len)
+ ret.Append (s2 [idx]);
+ }
+ else
+ ret.Append (s0 [pos]);
+
+ pos++;
+ }
+
+ return ret.ToString ();
+ }
+
+ public override string ToString ()
{
- throw new NotImplementedException ();
+ return String.Concat (new string [] {
+ "string-length(",
+ arg0.ToString (), ",",
+ arg1.ToString (), ",",
+ arg2.ToString (), ")"});
}
- public override string Name { get { return "translate"; }}
}
- internal class XPathFunctionBoolean : XPathFunction
+
+ internal abstract class XPathBooleanFunction : XPathFunction
{
+ public XPathBooleanFunction (FunctionArguments args) : base (args)
+ {
+ }
+
public override XPathResultType ReturnType { get { return XPathResultType.Boolean; }}
- public override int Minargs { get { return 1; }}
- public override int Maxargs { get { return 1; }}
- public override XPathResultType [] ArgTypes { get { return new XPathResultType [] { XPathResultType.Any }; }}
- public override object TypesafeInvoke (XsltContext xsltContext, object[] args, XPathNavigator docContext)
+
+ public override object StaticValue {
+ get { return StaticValueAsBoolean; }
+ }
+ }
+
+ internal class XPathFunctionBoolean : XPathBooleanFunction
+ {
+ Expression arg0;
+
+ public XPathFunctionBoolean (FunctionArguments args) : base (args)
+ {
+ if (args != null) {
+ arg0 = args.Arg;
+ if (args.Tail != null)
+ throw new XPathException ("boolean takes 1 or zero args");
+ }
+ }
+
+ internal override bool Peer {
+ get { return arg0 != null ? arg0.Peer : true; }
+ }
+
+ public override object Evaluate (BaseIterator iter)
+ {
+ if (arg0 == null)
+ return XPathFunctions.ToBoolean (iter.Current.Value);
+ return arg0.EvaluateBoolean (iter);
+ }
+
+ public override string ToString ()
{
- return XPathFunctions.ToBoolean (args [0]);
+ return String.Concat (new string [] {"boolean(", arg0.ToString (), ")"});
}
- public override string Name { get { return "boolean"; }}
}
- internal class XPathFunctionNot : XPathFunction
+
+
+ internal class XPathFunctionNot : XPathBooleanFunction
{
- public override XPathResultType ReturnType { get { return XPathResultType.Boolean; }}
- public override int Minargs { get { return 1; }}
- public override int Maxargs { get { return 1; }}
- public override XPathResultType [] ArgTypes { get { return new XPathResultType [] { XPathResultType.Any }; }}
- public override object TypesafeInvoke (XsltContext xsltContext, object[] args, XPathNavigator docContext)
+ Expression arg0;
+
+ public XPathFunctionNot (FunctionArguments args) : base (args)
+ {
+ if (args == null || args.Tail != null)
+ throw new XPathException ("not takes one arg");
+ arg0 = args.Arg;
+ }
+
+ internal override bool Peer {
+ get { return arg0.Peer; }
+ }
+
+ public override object Evaluate (BaseIterator iter)
+ {
+ return !arg0.EvaluateBoolean (iter);
+ }
+
+ public override string ToString ()
{
- return !(XPathFunctions.ToBoolean (args [0]));
+ return String.Concat (new string [] {"not(", arg0.ToString (), ")"});
}
- public override string Name { get { return "not"; }}
}
- internal class XPathFunctionTrue : XPathFunction
+
+
+ internal class XPathFunctionTrue : XPathBooleanFunction
{
- public override XPathResultType ReturnType { get { return XPathResultType.Boolean; }}
- public override int Minargs { get { return 0; }}
- public override int Maxargs { get { return 0; }}
- public override XPathResultType [] ArgTypes { get { return null; }}
- public override object TypesafeInvoke (XsltContext xsltContext, object[] args, XPathNavigator docContext)
+ public XPathFunctionTrue (FunctionArguments args) : base (args)
+ {
+ if (args != null)
+ throw new XPathException ("true takes 0 args");
+ }
+
+ public override bool HasStaticValue {
+ get { return true; }
+ }
+
+ public override bool StaticValueAsBoolean {
+ get { return true; }
+ }
+
+ internal override bool Peer {
+ get { return true; }
+ }
+
+ public override object Evaluate (BaseIterator iter)
{
return true;
}
- public override string Name { get { return "true"; }}
+
+ public override string ToString ()
+ {
+ return "true()";
+ }
}
- internal class XPathFunctionFalse : XPathFunction
+
+
+ internal class XPathFunctionFalse : XPathBooleanFunction
{
- public override XPathResultType ReturnType { get { return XPathResultType.Boolean; }}
- public override int Minargs { get { return 0; }}
- public override int Maxargs { get { return 0; }}
- public override XPathResultType [] ArgTypes { get { return null; }}
- public override object TypesafeInvoke (XsltContext xsltContext, object[] args, XPathNavigator docContext)
+ public XPathFunctionFalse (FunctionArguments args) : base (args)
+ {
+ if (args != null)
+ throw new XPathException ("false takes 0 args");
+ }
+
+ public override bool HasStaticValue {
+ get { return true; }
+ }
+
+ public override bool StaticValueAsBoolean {
+ get { return false; }
+ }
+
+ internal override bool Peer {
+ get { return true; }
+ }
+
+ public override object Evaluate (BaseIterator iter)
{
return false;
}
- public override string Name { get { return "false"; }}
+
+ public override string ToString ()
+ {
+ return "false()";
+ }
}
+
+
internal class XPathFunctionLang : XPathFunction
{
+ Expression arg0;
+
+ public XPathFunctionLang (FunctionArguments args) : base (args)
+ {
+ if (args == null || args.Tail != null)
+ throw new XPathException ("lang takes one arg");
+ arg0 = args.Arg;
+ }
+
public override XPathResultType ReturnType { get { return XPathResultType.Boolean; }}
- public override int Minargs { get { return 1; }}
- public override int Maxargs { get { return 1; }}
- public override XPathResultType [] ArgTypes { get { return new XPathResultType [] { XPathResultType.String }; }}
- [MonoTODO]
- public override object TypesafeInvoke (XsltContext xsltContext, object[] args, XPathNavigator docContext)
+
+ internal override bool Peer {
+ get { return arg0.Peer; }
+ }
+
+ public override object Evaluate (BaseIterator iter)
{
- throw new NotImplementedException ();
+ return EvaluateBoolean (iter);
+ }
+
+ public override bool EvaluateBoolean (BaseIterator iter)
+ {
+ string lang = arg0.EvaluateString (iter).ToLower (CultureInfo.InvariantCulture);
+ string actualLang = iter.Current.XmlLang.ToLower (CultureInfo.InvariantCulture);
+
+ return lang == actualLang || lang == (actualLang.Split ('-')[0]);
+ }
+
+ public override string ToString ()
+ {
+ return String.Concat (new string [] {"lang(", arg0.ToString (), ")"});
}
- public override string Name { get { return "lang"; }}
}
- internal class XPathFunctionNumber : XPathFunction
+
+ internal abstract class XPathNumericFunction : XPathFunction
{
+ internal XPathNumericFunction (FunctionArguments args)
+ : base (args)
+ {
+ }
+
public override XPathResultType ReturnType { get { return XPathResultType.Number; }}
- public override int Minargs { get { return 0; }}
- public override int Maxargs { get { return 1; }}
- public override XPathResultType [] ArgTypes { get { return new XPathResultType [] { XPathResultType.Any }; }}
- public override object TypesafeInvoke (XsltContext xsltContext, object[] args, XPathNavigator docContext)
+
+ public override object StaticValue {
+ get { return StaticValueAsNumber; }
+ }
+ }
+
+ internal class XPathFunctionNumber : XPathNumericFunction
+ {
+ Expression arg0;
+
+ public XPathFunctionNumber (FunctionArguments args) : base (args)
+ {
+ if (args != null) {
+ arg0 = args.Arg;
+ if (args.Tail != null)
+ throw new XPathException ("number takes 1 or zero args");
+ }
+ }
+
+ public override Expression Optimize ()
+ {
+ if (arg0 == null)
+ return this;
+ arg0 = arg0.Optimize ();
+ return !arg0.HasStaticValue ?
+ (Expression) this :
+ new ExprNumber (StaticValueAsNumber);
+ }
+
+ public override bool HasStaticValue {
+ get { return arg0 != null && arg0.HasStaticValue; }
+ }
+
+ public override double StaticValueAsNumber {
+ get { return arg0 != null ? arg0.StaticValueAsNumber : 0; }
+ }
+
+ internal override bool Peer {
+ get { return arg0 != null ? arg0.Peer : true; }
+ }
+
+ public override object Evaluate (BaseIterator iter)
+ {
+ if (arg0 == null)
+ return XPathFunctions.ToNumber (iter.Current.Value);
+ return arg0.EvaluateNumber (iter);
+ }
+
+ public override string ToString ()
{
- return XPathFunctions.ToNumber (args [0]);
+ return String.Concat (new string [] {"number(", arg0.ToString (), ")"});
}
- public override string Name { get { return "number"; }}
}
- internal class XPathFunctionSum : XPathFunction
+
+
+ internal class XPathFunctionSum : XPathNumericFunction
{
- public override XPathResultType ReturnType { get { return XPathResultType.Number; }}
- public override int Minargs { get { return 1; }}
- public override int Maxargs { get { return 1; }}
- public override XPathResultType [] ArgTypes { get { return new XPathResultType [] { XPathResultType.NodeSet }; }}
- [MonoTODO]
- public override object TypesafeInvoke (XsltContext xsltContext, object[] args, XPathNavigator docContext)
+ Expression arg0;
+
+ public XPathFunctionSum (FunctionArguments args) : base (args)
+ {
+ if (args == null || args.Tail != null)
+ throw new XPathException ("sum takes one arg");
+ arg0 = args.Arg;
+ }
+
+ internal override bool Peer {
+ get { return arg0.Peer; }
+ }
+
+ public override object Evaluate (BaseIterator iter)
{
- throw new NotImplementedException ();
+ XPathNodeIterator itr = arg0.EvaluateNodeSet (iter);
+
+ double sum = 0;
+ while (itr.MoveNext ())
+ sum += XPathFunctions.ToNumber (itr.Current.Value);
+
+ return sum;
+ }
+
+ public override string ToString ()
+ {
+ return String.Concat (new string [] {"sum(", arg0.ToString (), ")"});
}
- public override string Name { get { return "sum"; }}
}
- internal class XPathFunctionFloor : XPathFunction
+
+
+ internal class XPathFunctionFloor : XPathNumericFunction
{
- public override XPathResultType ReturnType { get { return XPathResultType.Number; }}
- public override int Minargs { get { return 1; }}
- public override int Maxargs { get { return 1; }}
- public override XPathResultType [] ArgTypes { get { return new XPathResultType [] { XPathResultType.Number }; }}
- public override object TypesafeInvoke (XsltContext xsltContext, object[] args, XPathNavigator docContext)
+ Expression arg0;
+
+ public XPathFunctionFloor (FunctionArguments args) : base (args)
+ {
+ if (args == null || args.Tail != null)
+ throw new XPathException ("floor takes one arg");
+ arg0 = args.Arg;
+ }
+
+ public override bool HasStaticValue {
+ get { return arg0.HasStaticValue; }
+ }
+
+ public override double StaticValueAsNumber {
+ get { return HasStaticValue ? Math.Floor (arg0.StaticValueAsNumber) : 0; }
+ }
+
+ internal override bool Peer {
+ get { return arg0.Peer; }
+ }
+
+ public override object Evaluate (BaseIterator iter)
+ {
+ return Math.Floor (arg0.EvaluateNumber (iter));
+ }
+
+ public override string ToString ()
{
- return Math.Floor ((double) args [0]);
+ return String.Concat (new string [] {"floor(", arg0.ToString (), ")"});
}
- public override string Name { get { return "floor"; }}
}
- internal class XPathFunctionCeil : XPathFunction
+
+
+ internal class XPathFunctionCeil : XPathNumericFunction
{
- public override XPathResultType ReturnType { get { return XPathResultType.Number; }}
- public override int Minargs { get { return 1; }}
- public override int Maxargs { get { return 1; }}
- public override XPathResultType [] ArgTypes { get { return new XPathResultType [] { XPathResultType.Number }; }}
- public override object TypesafeInvoke (XsltContext xsltContext, object[] args, XPathNavigator docContext)
+ Expression arg0;
+
+ public XPathFunctionCeil (FunctionArguments args) : base (args)
+ {
+ if (args == null || args.Tail != null)
+ throw new XPathException ("ceil takes one arg");
+ arg0 = args.Arg;
+ }
+
+ public override bool HasStaticValue {
+ get { return arg0.HasStaticValue; }
+ }
+
+ public override double StaticValueAsNumber {
+ get { return HasStaticValue ? Math.Ceiling (arg0.StaticValueAsNumber) : 0; }
+ }
+
+ internal override bool Peer {
+ get { return arg0.Peer; }
+ }
+
+ public override object Evaluate (BaseIterator iter)
+ {
+ return Math.Ceiling (arg0.EvaluateNumber (iter));
+ }
+
+ public override string ToString ()
{
- return Math.Ceiling ((double) args [0]);
+ return String.Concat (new string [] {"ceil(", arg0.ToString (), ")"});
}
- public override string Name { get { return "ceil"; }}
}
- internal class XPathFunctionRound : XPathFunction
+
+
+ internal class XPathFunctionRound : XPathNumericFunction
{
- public override XPathResultType ReturnType { get { return XPathResultType.Number; }}
- public override int Minargs { get { return 1; }}
- public override int Maxargs { get { return 1; }}
- public override XPathResultType [] ArgTypes { get { return new XPathResultType [] { XPathResultType.Number }; }}
- public override object TypesafeInvoke (XsltContext xsltContext, object[] args, XPathNavigator docContext)
+ Expression arg0;
+
+ public XPathFunctionRound (FunctionArguments args) : base (args)
+ {
+ if (args == null || args.Tail != null)
+ throw new XPathException ("round takes one arg");
+ arg0 = args.Arg;
+ }
+
+ public override bool HasStaticValue {
+ get { return arg0.HasStaticValue; }
+ }
+
+ public override double StaticValueAsNumber {
+ get { return HasStaticValue ? Round (arg0.StaticValueAsNumber) : 0; }
+ }
+
+ internal override bool Peer {
+ get { return arg0.Peer; }
+ }
+
+ public override object Evaluate (BaseIterator iter)
+ {
+ return Round (arg0.EvaluateNumber (iter));
+ }
+
+ private double Round (double arg)
{
- double arg = (double) args [0];
if (arg < -0.5 || arg > 0)
return Math.Floor (arg + 0.5);
return Math.Round (arg);
}
- public override string Name { get { return "round"; }}
+
+ public override string ToString ()
+ {
+ return String.Concat (new string [] {"round(", arg0.ToString (), ")"});
+ }
}
}