2003-12-16 Atsushi Enomoto <ginga@kit.hi-ho.ne.jp>
[mono.git] / mcs / class / System.XML / Mono.Xml.Xsl / XsltCompiledContext.cs
index 86da3e9c0c07d96ec7b1a233d28dfa6416bbdaf3..ace588872ac43874c04baf4bfc3b463ce6aeb95c 100644 (file)
@@ -32,7 +32,7 @@ namespace Mono.Xml.Xsl {
                        
                public XslTransformProcessor Processor { get { return p; }}
                        
-               public XsltCompiledContext (XslTransformProcessor p)
+               public XsltCompiledContext (XslTransformProcessor p) : base (new NameTable ())
                {
                        this.p = p;
                }
@@ -51,25 +51,35 @@ namespace Mono.Xml.Xsl {
 
                        string ns = name.Namespace;
 
-                       if (ns == null || p.Arguments == null) return null;
+                       if (ns == null) return null;
 
-                       object extension = p.Arguments.GetExtensionObject (ns);
-                               
-                       if (extension == null)
-                               return null;                    
+                       object extension = null;
+                       
+                       if (p.Arguments != null)
+                               extension = p.Arguments.GetExtensionObject (ns);
+                       
+                       bool isScript = false;
+                       if (extension == null) {
+                               extension = p.ScriptManager.GetExtensionObject (ns);
+                               if (extension == null)
+                                       return null;
+
+                               isScript = true;
+                       }
                        
-                       MethodInfo method = FindBestMethod (extension.GetType (), name.Name, argTypes);
+                       
+                       MethodInfo method = FindBestMethod (extension.GetType (), name.Name, argTypes, isScript);
                        
                        if (method != null) 
                                return new XsltExtensionFunction (extension, method);
                        return null;
                }
                
-               MethodInfo FindBestMethod (Type t, string name, XPathResultType [] argTypes)
+               MethodInfo FindBestMethod (Type t, string name, XPathResultType [] argTypes, bool isScript)
                {
                        int free, length;
                        
-                       MethodInfo [] mi = t.GetMethods (BF.Public | BF.Instance | BF.Static);
+                       MethodInfo [] mi = t.GetMethods ((isScript ? BF.Public | BF.NonPublic : BF.Public) | BF.Instance | BF.Static);
                        if (mi.Length == 0)
                                return null;
                        
@@ -140,8 +150,92 @@ namespace Mono.Xml.Xsl {
                }
 
                public override int CompareDocument (string baseUri, string nextBaseUri) { throw new NotImplementedException (); }
-               public override bool PreserveWhitespace (XPathNavigator nav) { throw new NotImplementedException (); }
-               public override bool Whitespace { get { throw new NotImplementedException (); }}
+
+               public override bool PreserveWhitespace (XPathNavigator nav) 
+               {
+                       /*
+                       XPathNavigator tmp = nav.Clone ();
+                       switch (tmp.NodeType) {
+                       case XPathNodeType.Root:
+                               return false;
+                       case XPathNodeType.Element:
+                               break;
+                       default:
+                               tmp.MoveToParent ();
+                               break;
+                       }
+
+                       for (; tmp.NodeType == XPathNodeType.Element; tmp.MoveToParent ()) {
+                               object o = p.CompiledStyle.Style.SpaceControls [new XmlQualifiedName (tmp.LocalName, tmp.NamespaceURI)];
+                       */
+                               object o = p.CompiledStyle.Style.SpaceControls [new XmlQualifiedName (nav.LocalName, nav.NamespaceURI)];
+                               if (o == null)
+//                                     continue;
+                                       return true;
+                               XmlSpace space = (XmlSpace) o;
+                               switch ((XmlSpace) o) {
+                               case XmlSpace.Preserve:
+                                       return true;
+                               case XmlSpace.Default:
+                                       return false;
+                               // None: continue.
+                               }
+                       return true; // temporary
+                       /*
+                       }
+                       return true;
+                       */
+               }
+
+               public override bool Whitespace { get { return WhitespaceHandling; } }
+
+               // Below are mimicking XmlNamespaceManager ;-)
+               public bool IsCData {
+                       get { return scopes [scopeAt].IsCData; }
+                       set { scopes [scopeAt].IsCData = value; }
+               }
+               public bool WhitespaceHandling {
+                       get { return scopes [scopeAt].PreserveWhitespace; }
+                       set { scopes [scopeAt].PreserveWhitespace = value; }
+               }
+
+               struct XsltContextInfo
+               {
+                       public bool IsCData;
+                       public bool PreserveWhitespace;
+               }
+               
+               // TODO: set 40 or so. It is set to 2 only for test.
+               XsltContextInfo [] scopes = new XsltContextInfo [2];
+               int scopeAt = 0;
+               
+               // precondition scopeAt == scopes.Length
+               void ExtendScope ()
+               {
+                       XsltContextInfo [] old = scopes;
+                       scopes = new XsltContextInfo [scopeAt * 2 + 1];
+                       if (scopeAt > 0)
+                               Array.Copy (old, 0, scopes, 0, scopeAt);
+               }
+
+               public override bool PopScope ()
+               {
+                       base.PopScope ();
+
+                       if (scopeAt == -1)
+                               return false;
+                       scopeAt--;
+                       return true;
+               }
+
+               public override void PushScope ()
+               {
+                       base.PushScope ();
+
+                       scopeAt++;
+                       if (scopeAt == scopes.Length)
+                               ExtendScope ();
+               }
        }
 
 
@@ -234,13 +328,50 @@ namespace Mono.Xml.Xsl.Functions {
                public override object Invoke (XsltCompiledContext xsltContext, object [] args, XPathNavigator docContext)
                {
                        try {
-                               object result = method.Invoke(extension, args);
+                               ParameterInfo [] pis = method.GetParameters ();
+                               object [] castedArgs = new object [pis.Length];
+                               for (int i = 0; i < args.Length; i++) {
+                                       Type t = pis [i].ParameterType;
+                                       switch (t.FullName) {
+                                       case "System.Int16":
+                                       case "System.UInt16":
+                                       case "System.Int32":
+                                       case "System.UInt32":
+                                       case "System.Int64":
+                                       case "System.UInt64":
+                                       case "System.Single":
+                                       case "System.Decimal":
+                                               castedArgs [i] = Convert.ChangeType (args [i], t);
+                                               break;
+                                       default:
+                                               castedArgs [i] = args [i];
+                                               break;
+                                       }
+                               }
+
+                               object result = null;
+                               switch (method.ReturnType.FullName) {
+                               case "System.Int16":
+                               case "System.UInt16":
+                               case "System.Int32":
+                               case "System.UInt32":
+                               case "System.Int64":
+                               case "System.UInt64":
+                               case "System.Single":
+                               case "System.Decimal":
+                                       result = (double) method.Invoke (extension, castedArgs);
+                                       break;
+                               default:
+                                       result = method.Invoke(extension, castedArgs);
+                                       break;
+                               }
                                IXPathNavigable navigable = result as IXPathNavigable;
                                if (navigable != null)
                                        return navigable.CreateNavigator ();
 
                                return result;
-                       } catch {
+                       } catch (Exception ex) {
+//                             throw new XsltException ("Custom function reported an error.", ex);
                                Debug.WriteLine ("****** INCORRECT RESOLUTION **********");
                                return "";
                        }
@@ -317,7 +448,7 @@ namespace Mono.Xml.Xsl.Functions {
                        Hashtable got = new Hashtable ();
                        
                        while (itr.MoveNext()) {
-                               Uri uri = Resolve (itr.Current.Value, baseUri != null ? baseUri : itr.Current.BaseURI, xsltContext.Processor);
+                               Uri uri = Resolve (itr.Current.Value, baseUri != null ? baseUri : /*itr.Current.BaseURI*/doc.BaseURI, xsltContext.Processor);
                                if (!got.ContainsKey (uri)) {
                                        got.Add (uri, null);
                                        if (uri.ToString () == "") {
@@ -522,7 +653,9 @@ namespace Mono.Xml.Xsl.Functions {
                        StringBuilder sb = new StringBuilder ("Mono"); // Ensure begins with alpha
                        sb.Append (XmlConvert.EncodeLocalName (n.BaseURI));
                        sb.Replace ('_', 'm'); // remove underscores from EncodeLocalName
-                       
+                       sb.Append (n.NodeType);
+                       sb.Append ('m');
+
                        do {
                                sb.Append (IndexInParent (n));
                                sb.Append ('m');
@@ -533,8 +666,6 @@ namespace Mono.Xml.Xsl.Functions {
                
                int IndexInParent (XPathNavigator nav)
                {
-                       nav = nav.Clone();
-                       
                        int n = 0;
                        while (nav.MoveToPrevious ())
                                n++;
@@ -594,7 +725,7 @@ namespace Mono.Xml.Xsl.Functions {
                                                do {
                                                        if (key.Matches (desc.Current, value))
                                                                AddResult (result, desc.Current);       
-                                               } while (desc.Current.MoveToNext ());
+                                               } while (desc.Current.MoveToNextAttribute ());
                                                
                                                desc.Current.MoveToParent ();
                                        }