2 // XsltCompiledContext.cs
5 // Ben Maurer (bmaurer@users.sourceforge.net)
12 using System.Collections;
13 using System.Collections.Specialized;
15 using System.Xml.Schema;
16 using System.Xml.XPath;
19 using Mono.Xml.Xsl.Functions;
20 using Mono.Xml.Xsl.Operations;
21 using System.Reflection;
22 using BF = System.Reflection.BindingFlags;
24 using QName = System.Xml.XmlQualifiedName;
27 namespace Mono.Xml.Xsl {
29 internal class XsltCompiledContext : XsltContext {
30 protected static Hashtable xsltFunctions = new Hashtable ();
32 static XsltCompiledContext ()
34 xsltFunctions.Add ("current", new XsltCurrent ());
35 xsltFunctions.Add ("document", new XsltDocument ());
36 xsltFunctions.Add ("element-available", new XsltElementAvailable ());
37 xsltFunctions.Add ("format-number", new XsltFormatNumber ());
38 xsltFunctions.Add ("function-available", new XsltFunctionAvailable ());
39 xsltFunctions.Add ("generate-id", new XsltGenerateId ());
40 xsltFunctions.Add ("key", new XsltKey ());
41 xsltFunctions.Add ("system-property", new XsltSystemProperty ());
42 xsltFunctions.Add ("unparsed-entity-uri", new XsltUnparsedEntityUri ());
45 XslTransformProcessor p;
48 public XslTransformProcessor Processor { get { return p; }}
50 public XsltCompiledContext (XslTransformProcessor p, VariableScope v)
56 public override string DefaultNamespace { get { return String.Empty; }}
59 public override string LookupNamespace (string prefix)
61 if (prefix == "" || prefix == null)
64 return p.CompiledStyle.NamespaceManager.LookupNamespace (prefix);
67 public override IXsltContextFunction ResolveFunction (string prefix, string name, XPathResultType[] argTypes)
69 IXsltContextFunction func = null;
70 if (prefix == String.Empty || prefix == null) {
71 return xsltFunctions [name] as IXsltContextFunction;
73 string ns = this.LookupNamespace (prefix);
75 if (ns == null || p.Arguments == null) return null;
77 object extension = p.Arguments.GetExtensionObject (ns);
79 if (extension == null)
82 MethodInfo method = FindBestMethod (extension.GetType (), name, argTypes);
85 return new XsltExtensionFunction (extension, method);
91 MethodInfo FindBestMethod (Type t, string name, XPathResultType [] argTypes)
95 MethodInfo [] mi = t.GetMethods (BF.Public | BF.Instance | BF.Static);
101 // filter on name + num args
102 int numArgs = argTypes == null ? 0 : argTypes.Length;
103 for (int i = 0; i < mi.Length; i ++) {
104 if (mi [i].Name == name && mi [i].GetParameters ().Length == numArgs)
105 mi [free++] = mi [i];
118 for (int i = 0; i < length; i ++) {
120 ParameterInfo [] pi = mi [i].GetParameters ();
122 for (int par = 0; par < pi.Length; par++) {
123 XPathResultType required = argTypes [par];
124 if (required == XPathResultType.Any)
125 continue; // dunno what it is
127 XPathResultType actual = XPFuncImpl.GetXPathType (pi [par].ParameterType);
128 if (actual != required && actual != XPathResultType.Any) {
133 if (actual == XPathResultType.Any) {
134 // try to get a stronger gind
135 if (required != XPathResultType.NodeSet && !(pi [par].ParameterType == typeof (object)))
142 if (match) return mi [i]; // TODO look for exact match
148 public override System.Xml.Xsl.IXsltContextVariable ResolveVariable(string prefix, string name)
151 XslGeneralVariable var = v.Resolve (p, new QName (name));
156 return p.CompiledStyle.ResolveVariable (new QName (name));
159 public override int CompareDocument (string baseUri, string nextBaseUri) { throw new NotImplementedException (); }
160 public override bool PreserveWhitespace (XPathNavigator nav) { throw new NotImplementedException (); }
161 public override bool Whitespace { get { throw new NotImplementedException (); }}
166 namespace Mono.Xml.Xsl.Functions {
168 internal abstract class XPFuncImpl : IXsltContextFunction {
169 int minargs, maxargs;
170 XPathResultType returnType;
171 XPathResultType [] argTypes;
173 public XPFuncImpl () {}
174 public XPFuncImpl (int minArgs, int maxArgs, XPathResultType returnType, XPathResultType[] argTypes)
176 this.Init(minArgs, maxArgs, returnType, argTypes);
179 protected void Init (int minArgs, int maxArgs, XPathResultType returnType, XPathResultType[] argTypes)
181 this.minargs = minArgs;
182 this.maxargs = maxArgs;
183 this.returnType = returnType;
184 this.argTypes = argTypes;
187 public int Minargs { get { return this.minargs; }}
188 public int Maxargs { get { return this.maxargs; }}
189 public XPathResultType ReturnType { get { return this.returnType; }}
190 public XPathResultType [] ArgTypes { get { return this.argTypes; }}
191 public object Invoke (XsltContext xsltContext, object [] args, XPathNavigator docContext)
193 return Invoke ((XsltCompiledContext)xsltContext, args, docContext);
196 public abstract object Invoke (XsltCompiledContext xsltContext, object [] args, XPathNavigator docContext);
198 public static XPathResultType GetXPathType (Type type) {
199 switch (Type.GetTypeCode(type)) {
200 case TypeCode.String:
201 return XPathResultType.String;
202 case TypeCode.Boolean:
203 return XPathResultType.Boolean;
204 case TypeCode.Object:
205 if (typeof (XPathNavigator).IsAssignableFrom (type) || typeof (IXPathNavigable).IsAssignableFrom (type))
206 return XPathResultType.Navigator;
208 if (typeof (XPathNodeIterator).IsAssignableFrom (type))
209 return XPathResultType.NodeSet;
211 return XPathResultType.Any;
212 case TypeCode.DateTime :
213 throw new Exception ();
215 return XPathResultType.Number;
220 class XsltExtensionFunction : XPFuncImpl {
221 private object extension;
222 private MethodInfo method;
223 private TypeCode [] typeCodes;
225 public XsltExtensionFunction (object extension, MethodInfo method)
227 this.extension = extension;
228 this.method = method;
230 ParameterInfo [] parameters = method.GetParameters ();
231 int minArgs = parameters.Length;
232 int maxArgs = parameters.Length;
234 this.typeCodes = new TypeCode [parameters.Length];
235 XPathResultType[] argTypes = new XPathResultType [parameters.Length];
237 bool canBeOpt = true;
238 for (int i = parameters.Length - 1; 0 <= i; i--) { // optionals at the end
239 typeCodes [i] = Type.GetTypeCode (parameters [i].ParameterType);
240 argTypes [i] = GetXPathType (parameters [i].ParameterType);
242 if (parameters[i].IsOptional)
248 base.Init (minArgs, maxArgs, GetXPathType (method.ReturnType), argTypes);
251 public override object Invoke (XsltCompiledContext xsltContext, object [] args, XPathNavigator docContext)
254 object result = method.Invoke(extension, args);
255 IXPathNavigable navigable = result as IXPathNavigable;
256 if (navigable != null)
257 return navigable.CreateNavigator ();
261 Debug.WriteLine ("****** INCORRECT RESOLUTION **********");
267 class XsltCurrent : XPFuncImpl {
268 public XsltCurrent () : base (0, 0, XPathResultType.NodeSet, null) {}
270 public override object Invoke (XsltCompiledContext xsltContext, object [] args, XPathNavigator docContext)
272 return new SelfIterator (xsltContext.Processor.CurrentNode, null);
276 class XsltDocument : XPFuncImpl {
277 public XsltDocument () : base (1, 2, XPathResultType.NodeSet, new XPathResultType [] { XPathResultType.Any, XPathResultType.NodeSet }) {}
279 public override object Invoke (XsltCompiledContext xsltContext, object [] args, XPathNavigator docContext)
281 throw new NotImplementedException ();
285 class XsltElementAvailable : XPFuncImpl {
286 public XsltElementAvailable () : base (1, 1, XPathResultType.Boolean, new XPathResultType [] { XPathResultType.String }) {}
288 public override object Invoke (XsltCompiledContext xsltContext, object [] args, XPathNavigator docContext)
290 throw new NotImplementedException ();
294 class XsltFormatNumber : XPFuncImpl {
295 public XsltFormatNumber () : base (2, 3, XPathResultType.String , new XPathResultType [] { XPathResultType.Number, XPathResultType.String, XPathResultType.String }) {}
297 public override object Invoke (XsltCompiledContext xsltContext, object [] args, XPathNavigator docContext)
299 throw new NotImplementedException ();
303 class XsltFunctionAvailable : XPFuncImpl {
304 public XsltFunctionAvailable () : base (1, 1, XPathResultType.Boolean, new XPathResultType [] { XPathResultType.String }) {}
306 public override object Invoke (XsltCompiledContext xsltContext, object [] args, XPathNavigator docContext)
308 throw new NotImplementedException ();
312 class XsltGenerateId : XPFuncImpl {
313 public XsltGenerateId () : base (0, 1, XPathResultType.String , new XPathResultType [] { XPathResultType.NodeSet }) {}
314 public override object Invoke (XsltCompiledContext xsltContext, object [] args, XPathNavigator docContext)
316 throw new NotImplementedException ();
320 class XsltKey : XPFuncImpl {
321 public XsltKey () : base (2, 2, XPathResultType.NodeSet, new XPathResultType [] { XPathResultType.String, XPathResultType.Any }) {}
323 public override object Invoke (XsltCompiledContext xsltContext, object [] args, XPathNavigator docContext)
325 throw new NotImplementedException ();
329 class XsltSystemProperty : XPFuncImpl {
330 public XsltSystemProperty () : base (1, 1, XPathResultType.String , new XPathResultType [] { XPathResultType.String }) {}
332 public override object Invoke (XsltCompiledContext xsltContext, object [] args, XPathNavigator docContext)
334 throw new NotImplementedException ();
338 class XsltUnparsedEntityUri : XPFuncImpl {
339 public XsltUnparsedEntityUri () : base (1, 1, XPathResultType.String , new XPathResultType [] { XPathResultType.String }) {}
341 public override object Invoke (XsltCompiledContext xsltContext, object [] args, XPathNavigator docContext)
343 throw new NotImplementedException ();