2004-03-01 Atsushi Enomoto <atsushi@ximian.com>
[mono.git] / mcs / class / System.XML / Mono.Xml.Xsl.Operations / XslVariable.cs
1 //
2 // XslVariable.cs
3 //
4 // Authors:
5 //      Ben Maurer (bmaurer@users.sourceforge.net)
6 //      Atsushi Enomoto (ginga@kit.hi-ho.ne.jp)
7 //      
8 // (C) 2003 Ben Maurer
9 // (C) 2003 Atsushi Enomoto
10 //
11
12 using System;
13 using System.Collections;
14 using System.Xml;
15 using System.Xml.XPath;
16 using System.Xml.Xsl;
17 using Mono.Xml.XPath;
18
19 using QName = System.Xml.XmlQualifiedName;
20
21 namespace Mono.Xml.Xsl.Operations {
22         
23         public class XslVariableInformation
24         {
25                 QName name;
26                 XPathExpression select;
27                 XslOperation content;
28                 
29                 public XslVariableInformation (Compiler c)
30                 {
31                         c.AssertAttribute ("name");
32                         name = c.ParseQNameAttribute ("name");
33                         try {
34                                 XmlConvert.VerifyName (name.Name);
35                         } catch (XmlException ex) {
36                                 throw new XsltCompileException ("Variable name is not qualified name.", ex, c.Input);
37                         }
38                         
39                         string sel = c.GetAttribute ("select");
40                         if (sel != null && sel != "" ) {
41                                 select = c.CompileExpression (c.GetAttribute ("select"));
42                                 // TODO assert empty
43                         } else  if (c.Input.MoveToFirstChild ()) {
44                                 content = c.CompileTemplateContent ();
45                                 c.Input.MoveToParent ();
46                         }
47                 }
48                 
49                 public object Evaluate (XslTransformProcessor p)
50                 {
51                         if (select != null) {
52                                 return p.Evaluate (select);
53                         } else if (content != null) {
54 //                              XmlNodeWriter w = new XmlNodeWriter (false);
55                                 DTMXPathDocumentWriter w = new DTMXPathDocumentWriter (p.CurrentNode.NameTable, 200);
56                                 Outputter outputter = new GenericOutputter(w, p.Outputs, null, true);
57                                 p.PushOutput (outputter);
58                                 content.Evaluate (p);
59                                 p.PopOutput ();
60 //                              return w.Document.CreateNavigator ().SelectChildren (XPathNodeType.All);
61                                 return w.CreateDocument ().CreateNavigator ().SelectChildren (XPathNodeType.All);
62                         } else {
63                                 return "";
64                         }
65                 }
66                 
67                 public QName Name { get { return name; }}
68         }
69         
70         public abstract class XslGeneralVariable : XslCompiledElement, IXsltContextVariable {
71                 protected XslVariableInformation var;   
72                 
73                 public XslGeneralVariable (Compiler c) : base (c) {}
74                 
75                 protected override void Compile (Compiler c)
76                 {
77                         this.var = new XslVariableInformation (c);
78                 }
79                 
80                 public override abstract void Evaluate (XslTransformProcessor p);
81                 protected abstract object GetValue (XslTransformProcessor p);
82                 
83                 
84                 public object Evaluate (XsltContext xsltContext)
85                 {       
86                         object value = GetValue (((XsltCompiledContext)xsltContext).Processor);
87                         
88                         if (value is XPathNodeIterator)                 
89                                 return ((XPathNodeIterator)value).Clone ();
90                         
91                         return value;
92                 }
93
94                 public QName Name {get {return  var.Name;}}
95                 public XPathResultType VariableType { get {return XPathResultType.Any;}}
96                 public abstract bool IsLocal { get; }
97                 public abstract bool IsParam { get; }
98         }
99         
100         public class XslGlobalVariable : XslGeneralVariable {
101                 public XslGlobalVariable (Compiler c) : base (c) {}
102                 static object busyObject = new Object ();
103                 
104                         
105                 public override void Evaluate (XslTransformProcessor p)
106                 {
107                         Hashtable varInfo = p.globalVariableTable;
108                         
109                         if (varInfo.Contains (this)) {
110                                 if (varInfo [this] == busyObject)
111                                         throw new Exception ("Circular Dependency");
112                                 return;
113                         }
114                         
115                         varInfo [this] = busyObject;
116                         varInfo [this] = var.Evaluate (p);
117                         
118                 }
119                 
120                 protected override object GetValue (XslTransformProcessor p)
121                 {
122                         Evaluate (p);
123                         return p.globalVariableTable [this];
124                 }
125                         
126                 public override bool IsLocal { get { return false; }}
127                 public override bool IsParam { get { return false; }}
128         }
129         
130         public class XslGlobalParam : XslGlobalVariable {
131                 bool overriden;
132                 object paramVal;
133                 
134                 public XslGlobalParam (Compiler c) : base (c) {}
135                         
136                 public void Override (XslTransformProcessor p, object paramVal)
137                 {
138                         Debug.Assert (!p.globalVariableTable.Contains (this), "Shouldn't have been evaluated by this point");
139                         
140                         p.globalVariableTable [this] = paramVal;
141                 }
142                 
143                 public override bool IsParam { get { return true; }}
144         }
145         
146         public class XslLocalVariable : XslGeneralVariable {
147                 protected int slot;
148                                 
149                 public XslLocalVariable (Compiler c) : base (c)
150                 {
151                         slot = c.AddVariable (this);
152                 }
153                 
154                 public override void Evaluate (XslTransformProcessor p)
155                 {       
156                         p.SetStackItem (slot, var.Evaluate (p));
157                 }
158                 
159                 protected override object GetValue (XslTransformProcessor p)
160                 {
161                         return p.GetStackItem (slot);
162                 }
163                 
164                 public bool IsEvaluated (XslTransformProcessor p)
165                 {
166                         return p.GetStackItem (slot) != null;
167                 }
168                 
169                 public override bool IsLocal { get { return true; }}
170                 public override bool IsParam { get { return false; }}
171         }
172         
173         public class XslLocalParam : XslLocalVariable {
174                 bool overriden;
175                 object paramVal;
176                 
177                 public XslLocalParam (Compiler c) : base (c) {}
178                 
179                 public override void Evaluate (XslTransformProcessor p)
180                 {               
181                         if (p.GetStackItem (slot) != null) return; // evaluated already
182                                 
183                         base.Evaluate (p);
184                 }
185                 
186                 public void Override (XslTransformProcessor p, object paramVal)
187                 {
188                         p.SetStackItem (slot, paramVal);
189                 }
190                 
191                 public override bool IsParam { get { return true; }}
192         }
193         
194         internal class XPathVariableBinding : Expression {
195                 XslGeneralVariable v;
196                 public XPathVariableBinding (XslGeneralVariable v)
197                 {
198                         this.v = v;
199                 }
200                 public override String ToString () { return "$" + v.Name.ToString (); }
201                 public override XPathResultType ReturnType { get { return XPathResultType.Any; }}
202                 public override XPathResultType GetReturnType (BaseIterator iter)
203                 {
204                         return XPathResultType.Any;
205                 }
206                 
207                 public override object Evaluate (BaseIterator iter)
208                 {
209                         return v.Evaluate (iter.NamespaceManager as XsltContext);
210                 }
211         }
212 }