2004-02-16 Atsushi Enomoto <atsushi@ximian.com>
authorAtsushi Eno <atsushieno@gmail.com>
Mon, 16 Feb 2004 18:52:05 +0000 (18:52 -0000)
committerAtsushi Eno <atsushieno@gmail.com>
Mon, 16 Feb 2004 18:52:05 +0000 (18:52 -0000)
* XslKey.cs : Now it collects key and matching nodes at the first
  evaluation time. After that, we can just get them from the table.
* Compiler.cs : Added KeyCompilationMode. It is used to prevent
  prohibited key() usage in "match" and "use" attributes in xsl:key.
  Modified accessibility of some classes.
* GenericOutputter.cs,
  HtmlEmitter.cs,
  TextEmitter.cs,
  TextOutputter.cs,
  XmlWriterEmitter.cs : made classes internal.
* XslOutput.cs : support line info for exception.
* XsltCompiledContext.cs : implemented CompareDocument() - so easily.

svn path=/trunk/mcs/; revision=23141

mcs/class/System.XML/Mono.Xml.Xsl/ChangeLog
mcs/class/System.XML/Mono.Xml.Xsl/Compiler.cs
mcs/class/System.XML/Mono.Xml.Xsl/GenericOutputter.cs
mcs/class/System.XML/Mono.Xml.Xsl/HtmlEmitter.cs
mcs/class/System.XML/Mono.Xml.Xsl/TextEmitter.cs
mcs/class/System.XML/Mono.Xml.Xsl/TextOutputter.cs
mcs/class/System.XML/Mono.Xml.Xsl/XmlWriterEmitter.cs
mcs/class/System.XML/Mono.Xml.Xsl/XslKey.cs
mcs/class/System.XML/Mono.Xml.Xsl/XslOutput.cs
mcs/class/System.XML/Mono.Xml.Xsl/XsltCompiledContext.cs

index 8f4d3b06b243600045f7610accb8fdcbb839809c..59ba1cfdf1dda2393f152610a4cb39904a95f530 100644 (file)
@@ -1,3 +1,18 @@
+2004-02-16 Atsushi Enomoto <atsushi@ximian.com>
+
+       * XslKey.cs : Now it collects key and matching nodes at the first
+         evaluation time. After that, we can just get them from the table.
+       * Compiler.cs : Added KeyCompilationMode. It is used to prevent
+         prohibited key() usage in "match" and "use" attributes in xsl:key.
+         Modified accessibility of some classes.
+       * GenericOutputter.cs,
+         HtmlEmitter.cs,
+         TextEmitter.cs,
+         TextOutputter.cs,
+         XmlWriterEmitter.cs : made classes internal.
+       * XslOutput.cs : support line info for exception.
+       * XsltCompiledContext.cs : implemented CompareDocument() - so easily.
+
 2004-02-13 Atsushi Enomoto <atsushi@ximian.com>
 
        * XsltCompiledContext.cs : fixed the length of context info array.
index 4c590a385008d93cbc3c9209c2e094934fc8b4e6..42c3ddfa42fc31a9076ec33879c05fadf0be06d7 100644 (file)
@@ -102,7 +102,8 @@ namespace Mono.Xml.Xsl {
 
                XslStylesheet rootStyle;
                Hashtable outputs = new Hashtable ();
-                               
+               bool keyCompilationMode;        
+       
                public CompiledStylesheet Compile (XPathNavigator nav, XmlResolver res, Evidence evidence)
                {
                        this.parser = new XPathParser (this);
@@ -135,7 +136,12 @@ namespace Mono.Xml.Xsl {
                        get { return msScripts; }
                }
 
-               public Evidence Evidence {
+               public bool KeyCompilationMode {
+                       get { return keyCompilationMode; }
+                       set { keyCompilationMode = value; }
+               }
+
+               internal Evidence Evidence {
                        get { return evidence; }
                }
                
@@ -304,11 +310,11 @@ namespace Mono.Xml.Xsl {
                }
 
                internal XPathParser parser;
-               public XPathExpression CompileExpression (string expression)
+               internal CompiledExpression CompileExpression (string expression)
                {
                        if (expression == null || expression == "") return null;
 
-                       XPathExpression e = new CompiledExpression (parser.Compile (expression));
+                       CompiledExpression e = new CompiledExpression (parser.Compile (expression), true);
                        
                        exprStore.AddExpression (e, this);
                        
@@ -489,7 +495,10 @@ namespace Mono.Xml.Xsl {
                                case "function-available": return new XsltFunctionAvailable (args, this);
                                case "generate-id": return new XsltGenerateId (args);
                                case "format-number": return new XsltFormatNumber (args, this);
-                               case "key": return new XsltKey (args, this);
+                               case "key":
+                                       if (KeyCompilationMode)
+                                               throw new XsltCompileException ("Cannot use key() function inside key definition.", null, this.Input);
+                                       return new XsltKey (args, this);
                                case "document": return new XsltDocument (args, this);
                        }
                        
@@ -708,7 +717,7 @@ namespace Mono.Xml.Xsl {
                }
        }
        
-       public class XslNameUtil
+       internal class XslNameUtil
        {
                public static QName [] FromListString (string names, XPathNavigator current)
                {
@@ -771,7 +780,7 @@ namespace Mono.Xml.Xsl {
                }
        }
        
-       public class XPathNavigatorNsm : XmlNamespaceManager {
+       internal class XPathNavigatorNsm : XmlNamespaceManager {
                XPathNavigator nsScope;
                
                public XPathNavigatorNsm (XPathNavigator n) : base () {
index 5b6f93604bd1e1397315f03ecf1a88e0ac021e34..b120e28bda66325fbf8eb5b1714a025d0f47d885 100644 (file)
@@ -23,7 +23,7 @@ namespace Mono.Xml.Xsl
        /// Implements attributes dublicate checking, nemaspace stuff and
        /// choosing of right Emitter implementation.
        /// </summary>
-       public class GenericOutputter : Outputter {     
+       internal class GenericOutputter : Outputter {   
                private Hashtable _outputs;
                //Current xsl:output 
                private XslOutput _currentOutput;
@@ -109,7 +109,7 @@ namespace Mono.Xml.Xsl
                {
                        XslOutput xslOutput = (XslOutput)_outputs [String.Empty];
                        switch (xslOutput.Method) {
-                               case OutputMethod.Unknown: //TODO: handle xml vs html
+                               case OutputMethod.Unknown:
                                        if (localName != null && localName.ToLower () == "html" && ns == String.Empty)
                                                goto case OutputMethod.HTML;
                                        goto case OutputMethod.XML;
@@ -126,7 +126,7 @@ namespace Mono.Xml.Xsl
                                        _emitter = new TextEmitter (pendingTextWriter);
                                        break;
                                case OutputMethod.Custom:
-                                       throw new NotImplementedException ("Custom output method is not implemented yet.");
+                                       throw new NotSupportedException ("Custom output method is not supported in this version.");
                        }
                        pendingTextWriter = null;
                }
index 7c9ffa8723de44ffb1ae5cdde87d2955f2e3071b..761ce08d82df0672757f1b92af302daa06381dd2 100644 (file)
@@ -19,7 +19,7 @@ using System.Xml;
 
 namespace Mono.Xml.Xsl
 {
-       public class HtmlEmitter : Emitter
+       internal class HtmlEmitter : Emitter
        {
                TextWriter writer;
                Stack elementNameStack;
index b0d469c2ad83a95cf59c1e281d6f651ef1da8dc7..b3e1c110cb843453abf1cd639274015dd9f465b8 100644 (file)
@@ -18,7 +18,7 @@ namespace Mono.Xml.Xsl
        /// <summary>
        /// Emitetr, which emits result tree according to "text" output method.
        /// </summary>
-       public class TextEmitter : Emitter 
+       internal class TextEmitter : Emitter 
        {
                TextWriter writer;
                        
index 891a7b4915dd17b833d7a1bb6ca93f66c56d0ae6..e2afb04d1100723c6aadfb98084be1b45db2d9c3 100644 (file)
@@ -15,7 +15,7 @@ namespace Mono.Xml.Xsl {
        /// <summary>
        /// Outputter implementation for text output method.
        /// </summary>
-       public class TextOutputter : Outputter {
+       internal class TextOutputter : Outputter {
                private TextWriter _writer;
                //Current output depth
                private int _depth;             
index 348b42d9d47c09712debd23170cf548621f75460..62e6ae9b0846a5484d2fa5ce2f3253e5aadefada 100644 (file)
@@ -18,7 +18,7 @@ namespace Mono.Xml.Xsl
        /// <summary>
        /// Emitter, which emits result tree to a XmlWriter.
        /// </summary>
-       public class XmlWriterEmitter : Emitter 
+       internal class XmlWriterEmitter : Emitter 
        {
                XmlWriter writer;
                        
index 7b1f25fb4528b179a447ec32f637a29e5175668e..c311aa43ac0ccae2ea30972568f4a2bfb11a45c6 100644 (file)
@@ -20,60 +20,140 @@ using System.Xml.Xsl;
 
 using QName = System.Xml.XmlQualifiedName;
 
-namespace Mono.Xml.Xsl {
-       public class XslKey {
+namespace Mono.Xml.Xsl
+{
+       public class XslKey
+       {
                QName name;
-               XPathExpression usePattern;
-               XPathExpression matchPattern;
+               CompiledExpression usePattern;
+               CompiledExpression matchPattern;
+               Hashtable map;
+               Hashtable mappedDocuments;
 
                public XslKey (Compiler c)
                {
                        this.name = c.ParseQNameAttribute ("name");
-                       
+
+                       c.KeyCompilationMode = true;
                        usePattern = c.CompileExpression (c.GetAttribute ("use"));
                        if (usePattern == null)
                                usePattern = c.CompileExpression (".");
 
                        c.AssertAttribute ("match");
-                       this.matchPattern = c.CompileExpression (c.GetAttribute ("match"));
+                       string matchString = c.GetAttribute ("match");
+                       this.matchPattern = c.CompileExpression (matchString);
+                       c.KeyCompilationMode = false;
                }
 
                public QName Name { get { return name; }}
-               public XPathExpression UsePattern { get { return usePattern; }}
-               public XPathExpression MatchPattern { get { return matchPattern; }}
-               
-               public bool Matches (XPathNavigator nav, XmlNamespaceManager nsmgr, string value)
+               internal CompiledExpression UsePattern { get { return usePattern; }}
+               internal CompiledExpression MatchPattern { get { return matchPattern; }}
+
+               internal void ClearKeyTable ()
                {
-                       MatchPattern.SetContext (nsmgr);
-                       UsePattern.SetContext (nsmgr);
-                       if (!nav.Matches (MatchPattern)) 
-                               return false;
-//                     Debug.WriteLine ("? " + nav.Name);
-                       switch (UsePattern.ReturnType)
-                       {
+                       if (map != null) {
+                               map.Clear ();
+                               map = null;
+                       }
+                       if (mappedDocuments != null) {
+                               mappedDocuments.Clear ();
+                               mappedDocuments = null;
+                       }
+               }
+
+               internal void CollectTable (XPathNavigator doc)
+               {
+                       XPathNavigator nav = doc.Clone ();
+                       nav.MoveToRoot ();
+//                     if (MatchPattern.ExpressionNode.IsAbsolutePath)
+//                             CollectAbsoluteMatchNodes (nav);
+//                     else
+                               CollectRelativeMatchNodes (nav);
+               }
+
+               private void CollectAbsoluteMatchNodes (XPathNavigator nav)
+               {
+                       XPathNodeIterator iter = nav.Select (MatchPattern);
+                       while (iter.MoveNext ())
+                               CollectIndex (iter.Current);
+               }
+
+               private void CollectRelativeMatchNodes (XPathNavigator nav)
+               {
+                       do {
+                               if (nav.NodeType != XPathNodeType.Root)
+                                       while (!nav.MoveToNext ())
+                                               if (!nav.MoveToParent ())
+                                                       // finished
+                                                       return;
+                               do {
+                                       do {
+                                               if (nav.Matches (MatchPattern))
+                                                       CollectIndex (nav);
+                                       } while (nav.MoveToFirstChild ());
+                               } while (nav.MoveToNext ());
+                       } while (nav.MoveToParent ());
+               }
+
+               private void CollectIndex (XPathNavigator nav)
+               {
+                       XPathNavigator target = nav.Clone ();
+                       XPathNodeIterator iter;
+                       switch (UsePattern.ReturnType) {
                        case XPathResultType.NodeSet:
-                               XPathNodeIterator matches = nav.Select (UsePattern);
-                               while (matches.MoveNext ()) {
-                                       if (matches.Current.Value == value)
-                                               return true;
-                               }
-                               
-                               return false;
+                               iter = nav.Select (UsePattern);
+                               while (iter.MoveNext ())
+                                       AddIndex (iter.Current.Value, target);
+                               break;
                        case XPathResultType.Any:
-                               
                                object o = nav.Evaluate (UsePattern);
-                               if (o is XPathNodeIterator) {
-                                       XPathNodeIterator it = (XPathNodeIterator)o;
-                                       while (it.MoveNext ())
-                                               if (it.Current.Value == value)
-                                                       return true;
-                                       return false;
-                               } else {
-                                       return value == XPathFunctions.ToString (o);
+                               iter = o as XPathNodeIterator;
+                               if (iter != null) {
+                                       while (iter.MoveNext ())
+                                               AddIndex (iter.Current.Value, target);
                                }
+                               else
+                                       AddIndex (nav.EvaluateString (UsePattern, null, null), target);
+                               break;
                        default:
-                               return value == nav.EvaluateString (UsePattern, null, null);
+                               string key = nav.EvaluateString (UsePattern, null, null);
+                               AddIndex (key, target);
+                               break;
+                       }
+               }
+
+               private void AddIndex (string key, XPathNavigator target)
+               {
+                       ArrayList al = map [key] as ArrayList;
+                       if (al == null) {
+                               al = new ArrayList ();
+                               map [key] = al;
                        }
+                       al.Add (target);
+               }
+
+               public bool Matches (XPathNavigator nav, XmlNamespaceManager nsmgr, string value)
+               {
+                       if (map == null) {
+                               mappedDocuments = new Hashtable ();
+                               map = new Hashtable ();
+                       }
+                       if (mappedDocuments [nav.BaseURI] == null) {
+                               mappedDocuments.Add (nav.BaseURI, nav.BaseURI);
+                               MatchPattern.SetContext (nsmgr);
+                               UsePattern.SetContext (nsmgr);
+                               CollectTable (nav);
+                               MatchPattern.SetContext (null);
+                               UsePattern.SetContext (null);
+                       }
+                       
+                       ArrayList al = map [value] as ArrayList;
+                       if (al == null)
+                               return false;
+                       for (int i = 0; i < al.Count; i++)
+                               if (((XPathNavigator) al [i]).IsSamePosition (nav))
+                                       return true;
+                       return false;
                }
        }
 }
\ No newline at end of file
index d39fcce407add1f640cfb36e5241188616ed7759..4b2c9ee529fdf8baa847c9be2a96654680f92800 100644 (file)
@@ -146,23 +146,27 @@ namespace Mono.Xml.Xsl
 
                        if (att != String.Empty) {
                                switch (att) {
-                                       case "xml":
-                                               method = OutputMethod.XML;
-                                               break;
-                                       case "html":
-                                               method = OutputMethod.HTML;
-                                               break;
-                                       case "text":
-                                               method = OutputMethod.Text;
-                                               break;
-                                       default:
-                                               method = OutputMethod.Custom;
-                                               customMethod = XslNameUtil.FromString (att, nav);
-                                               if (customMethod.Namespace == String.Empty)
-                                                       //TODO: how to get current line number and position?
-                                                       throw new XsltCompileException(new ArgumentException("Invalid output method value: '" + att + 
-                                                       "'. It must be either 'xml' or 'html' or 'text' or QName."), nav.BaseURI, 1, 1);
-                                               break;
+                               case "xml":
+                                       method = OutputMethod.XML;
+                                       break;
+                               case "html":
+                                       method = OutputMethod.HTML;
+                                       break;
+                               case "text":
+                                       method = OutputMethod.Text;
+                                       break;
+                               default:
+                                       method = OutputMethod.Custom;
+                                       customMethod = XslNameUtil.FromString (att, nav);
+                                       if (customMethod.Namespace == String.Empty) {
+                                               IXmlLineInfo li = nav as IXmlLineInfo;
+                                               throw new XsltCompileException (new ArgumentException ("Invalid output method value: '" + att + 
+                                                       "'. It must be either 'xml' or 'html' or 'text' or QName."),
+                                                       nav.BaseURI,
+                                                       li != null ? li.LineNumber : 0,
+                                                       li != null ? li.LinePosition : 0);
+                                       }
+                                       break;
                                }
                        }
 
index e89bcb61cb5d2370534f7838e075cf63bed0a258..c68545c03bbe036dff6f98c8ca8922c0997c2ffb 100644 (file)
@@ -147,7 +147,11 @@ namespace Mono.Xml.Xsl {
                        return p.CompiledStyle.ResolveVariable (q);
                }
 
-               public override int CompareDocument (string baseUri, string nextBaseUri) { throw new NotImplementedException (); }
+               public override int CompareDocument (string baseUri, string nextBaseUri) 
+               {
+                       // it is implementation specific
+                       return baseUri.GetHashCode ().CompareTo (nextBaseUri.GetHashCode ());
+               }
 
                public override bool PreserveWhitespace (XPathNavigator nav) 
                {