Here comes managed XSLT! WOOOOOHOOOOOO!
[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
18 using QName = System.Xml.XmlQualifiedName;
19
20 namespace Mono.Xml.Xsl.Operations {
21         public abstract class XslGeneralVariable : XslCompiledElement, IXsltContextVariable {
22                 protected QName name;
23                 protected XPathExpression select;
24                 protected XslOperation content;
25                 protected object value;
26                 protected bool busy, evaluated;
27                 
28                 
29                 public XslGeneralVariable (Compiler c) : base (c) {}
30                 
31                 protected override void Compile (Compiler c)
32                 {
33                         c.AssertAttribute ("name");
34                         name = c.ParseQNameAttribute ("name");
35                         
36                         string sel = c.GetAttribute ("select");
37                         if (sel != null && sel != "" ) {
38                                 select = c.CompileExpression (c.GetAttribute ("select"));
39                                 // TODO assert empty
40                         } else  if (c.Input.MoveToFirstChild ()) {
41                                 content = c.CompileTemplateContent ();
42                                 c.Input.MoveToParent ();
43                         }
44                 }
45                 
46                 public override void Evaluate (XslTransformProcessor p) {
47                         Debug.WriteLine ("EVALUATING : " + name);
48                         Evaluate (p, false);
49                 }
50                 
51                 protected virtual void Evaluate (XslTransformProcessor p, bool isFromXPath)
52                 {
53                         if (!evaluated) {
54                                 if (busy) throw new Exception ("Circular dependency");
55                                 busy = true;
56                                 
57                                 if (select != null) {
58                                         value = p.Evaluate (select);
59                                 } else if (content != null) {
60                                         XmlNodeWriter w = new XmlNodeWriter ();
61                                         p.PushOutput (w);
62                                         content.Evaluate (p);
63                                         p.PopOutput ();
64                                         value = w.Document.CreateNavigator ().SelectChildren (XPathNodeType.All);
65                                 } else {
66                                         value = "";
67                                 }
68                                 if (value is XPathNodeIterator) 
69                                         Debug.WriteLine (name + " has " + ((XPathNodeIterator)value).Count + " elements.");
70                                 
71                                 evaluated = true;
72                                 busy = false;
73                         }
74                         
75                 }
76                 
77                 public QName Name {get {return this.name;}}
78                 
79                 public XPathResultType VariableType { 
80                         get {
81                                 if (value != null) return Functions.XPFuncImpl.GetXPathType (value.GetType ());
82                                 return XPathResultType.Any;
83                         }
84                 }
85                 
86                 public object Evaluate (XsltContext xsltContext)
87                 {
88                         if (!evaluated)
89                                 Evaluate (((XsltCompiledContext)xsltContext).Processor, true);
90                         
91                         if (value is XPathNodeIterator)                 
92                                 return ((XPathNodeIterator)value).Clone ();
93                         
94                         return value;
95                         
96                 }
97                 
98                                 
99                 public virtual void Clear ()
100                 {
101                         evaluated = false;
102                         value = null;
103                 }
104                 
105                 public bool Evaluated { get { return evaluated; }}
106                 public abstract bool IsLocal { get; }
107                 public abstract bool IsParam { get; }
108         }
109         
110         public class XslGlobalVariable : XslGeneralVariable {
111                 public XslGlobalVariable (Compiler c) : base (c) {}
112                 public override bool IsLocal { get { return false; }}
113                 public override bool IsParam { get { return false; }}
114         }
115         
116         public class XslGlobalParam : XslGlobalVariable {
117                 bool overriden;
118                 object paramVal;
119                 
120                 public XslGlobalParam (Compiler c) : base (c) {}
121                         
122                 public void Override (object paramVal)
123                 {
124                         if (evaluated)
125                                 throw new Exception ("why was i called again?");
126                         evaluated = true;
127                         
128                         this.value = paramVal;
129                 }
130                 public override bool IsParam { get { return true; }}
131         }
132         
133         public class XslLocalVariable : XslGeneralVariable {
134                 protected Stack values;
135                         
136                 public XslLocalVariable (Compiler c) : base (c)
137                 {
138                         c.AddVariable (this);
139                 }
140                 public override bool IsLocal { get { return true; }}
141                 public override bool IsParam { get { return false; }}
142                 
143                 protected override void Evaluate (XslTransformProcessor p, bool isFromXPath)
144                 {
145                         if (!evaluated && isFromXPath)
146                                 throw new Exception ("Variable used before decleration");
147                         
148                         if (evaluated && !isFromXPath) {
149                                 if (values == null)
150                                         values = new Stack ();
151                                 values.Push (value);
152                         }
153                         
154                         base.Evaluate (p, isFromXPath);
155                 }
156                 
157                 public override void Clear ()
158                 {
159                         base.Clear ();
160                         if (values != null && values.Count != 0) {
161                                 value = values.Pop ();
162                                 evaluated = true;
163                         }
164                 }
165         }
166         
167         public class XslLocalParam : XslLocalVariable {
168                 bool overriden;
169                 object paramVal;
170                 
171                 public XslLocalParam (Compiler c) : base (c) {}
172                         
173                 public void Override (object paramVal)
174                 {
175                         if (evaluated) {
176                                 if (values == null)
177                                         values = new Stack ();
178                                 values.Push (value);
179                         }
180                         evaluated = true;
181                         
182                         this.value = paramVal;
183                 }
184                 public override bool IsParam { get { return true; }}
185         }
186         
187         public class XslWithParam : XslGeneralVariable {
188                 public XslWithParam (Compiler c) : base (c) {}
189                 public override bool IsLocal { get { return false; }}
190                 public override bool IsParam { get { return false; }}
191                 
192                 public object Value {
193                         get {
194                                 if (!evaluated) throw new Exception ("why wasn't I evaluated");
195                                 if (value is XPathNodeIterator) return ((XPathNodeIterator)value).Clone ();
196                                 return value;
197                         }
198                 }
199         }
200 }