2003-07-30 Ben Maurer <bmaurer@users.sourceforge.net>
[mono.git] / mcs / class / System.XML / Mono.Xml.Xsl / XslTransformProcessor.cs
1 //
2 // XslTransformProcessor.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.Xsl.Operations;
18
19 using QName = System.Xml.XmlQualifiedName;
20
21 namespace Mono.Xml.Xsl {
22         public class XslTransformProcessor {
23                 CompiledStylesheet compiledStyle;
24                 
25                 XslStylesheet style;
26                 
27                 Stack currentTemplateStack = new Stack ();
28                 
29                 XPathNavigator root;
30                 XsltContext ctx;
31                 XsltArgumentList args;
32
33                 // Store the values of global params
34                 internal Hashtable globalVariableTable = new Hashtable ();
35                 
36                 public XslTransformProcessor (CompiledStylesheet style)
37                 {
38                         this.compiledStyle = style;
39                         this.style = style.Style;
40                 }
41
42                 public void Process (XPathNavigator root, XmlWriter output, XsltArgumentList args)
43                 {
44                         foreach (XslGlobalVariable v in CompiledStyle.Variables.Values) {
45                                 if (v is XslGlobalParam) {
46                                         object p = args.GetParam(v.Name.Name, v.Name.Namespace);
47                                         if (p != null)
48                                                 ((XslGlobalParam)v).Override (this, p);
49                                 }
50                         }
51                         
52                         this.args = args;
53                         this.root = root;
54                         this.outputStack.Push (output);
55                         this.ApplyTemplates (root.Select ("."), QName.Empty, null);
56                 }
57                 
58                 public XsltContext Context { get { return ctx; }}
59                 public CompiledStylesheet CompiledStyle { get { return compiledStyle; }}
60                 public XsltArgumentList Arguments {get{return args;}}
61                 
62                 #region Output
63                 Stack outputStack = new Stack ();
64                 
65                 public XmlWriter Out { get { return (XmlWriter)outputStack.Peek(); }}
66                 
67                 public void PushOutput (XmlWriter newOutput)
68                 {
69                         this.outputStack.Push (newOutput);
70                 }
71                 
72                 public XmlWriter PopOutput ()
73                 {
74                         return (XmlWriter)this.outputStack.Pop ();
75                 }
76                 #endregion
77                 
78                 #region Templates -- Apply/Call
79                 public void ApplyTemplates (XPathNodeIterator nodes, QName mode, Hashtable withParams)
80                 {
81                         PushNodeset (nodes);
82                         while (NodesetMoveNext ()) {
83                                 XslTemplate t = FindTemplate (CurrentNode, mode);
84                                 currentTemplateStack.Push (t);
85                                 t.Evaluate (this, withParams);
86                                 currentTemplateStack.Pop ();
87                         }
88                         
89                         PopNodeset ();
90                 }
91                 
92                 public void CallTemplate (QName name, Hashtable withParams)
93                 {
94                         XslTemplate t = FindTemplate (name);
95                         currentTemplateStack.Push (null);
96                         t.Evaluate (this, withParams);
97                         currentTemplateStack.Pop ();
98                 }
99                 
100                 public void ApplyImports ()
101                 {       
102
103                         XslTemplate currentTemplate = (XslTemplate)currentTemplateStack.Peek();
104                         if (currentTemplate == null) throw new Exception ("Invalid context for apply-imports");
105                         XslTemplate t;
106                         
107                         for (int i = currentTemplate.Parent.Imports.Count - 1; i >= 0; i--) {
108                                 XslStylesheet s = (XslStylesheet)currentTemplate.Parent.Imports [i];
109                                 t = s.Templates.FindMatch (CurrentNode, currentTemplate.Mode);
110                                 if (t != null) {                                        
111                                         currentTemplateStack.Push (t);
112                                         t.Evaluate (this);
113                                         currentTemplateStack.Pop ();
114                                         return;
115                                 }
116                         }
117                         
118                         switch (CurrentNode.NodeType) {
119                         case XPathNodeType.Root:
120                         case XPathNodeType.Element:
121                                 if (currentTemplate.Mode == QName.Empty)
122                                         t = XslDefaultNodeTemplate.Instance;
123                                 else
124                                         t = new XslDefaultNodeTemplate(currentTemplate.Mode);
125                         
126                                 break;
127                         case XPathNodeType.Attribute:
128                         case XPathNodeType.SignificantWhitespace:
129                         case XPathNodeType.Text:
130                         case XPathNodeType.Whitespace:
131                                 t = XslDefaultTextTemplate.Instance;
132                                 break;
133                         
134                         case XPathNodeType.Comment:
135                         case XPathNodeType.ProcessingInstruction:
136                                 t = XslEmptyTemplate.Instance;
137                                 break;
138                         
139                         default:
140                                 t = XslEmptyTemplate.Instance;
141                                 break;
142                         }
143                         currentTemplateStack.Push (t);
144                         t.Evaluate (this);
145                         currentTemplateStack.Pop ();
146                 }
147                 
148                 XslTemplate FindTemplate (XPathNavigator node, QName mode)
149                 {
150                         XslTemplate ret = style.Templates.FindMatch (CurrentNode, mode);
151                         
152                         if (ret != null) return ret;
153
154                         switch (node.NodeType) {
155                         case XPathNodeType.Root:
156                         case XPathNodeType.Element:
157                                 if (mode == QName.Empty)
158                                         return XslDefaultNodeTemplate.Instance;
159                                 else
160                                         return new XslDefaultNodeTemplate(mode);
161                         
162                         case XPathNodeType.Attribute:
163                         case XPathNodeType.SignificantWhitespace:
164                         case XPathNodeType.Text:
165                         case XPathNodeType.Whitespace:
166                                 return XslDefaultTextTemplate.Instance;
167                         
168                         case XPathNodeType.Comment:
169                         case XPathNodeType.ProcessingInstruction:
170                                 return XslEmptyTemplate.Instance;
171                         
172                         default:
173                                 return XslEmptyTemplate.Instance;
174                         }
175                 }
176                 
177                 XslTemplate FindTemplate (QName name)
178                 {
179                         XslTemplate ret = style.Templates.FindTemplate (name);
180                         if (ret != null) return ret;
181                                 
182                         throw new Exception ("Could not resolve named template " + name);
183                 }
184                 
185                 #endregion
186                 
187
188                 public void PushForEachContext ()
189                 {
190                         currentTemplateStack.Push (null);
191                 }
192                 
193                 public void PopForEachContext ()
194                 {
195                         currentTemplateStack.Pop ();
196                 }
197                 
198
199                 #region Nodeset Context
200                 Stack nodesetStack = new Stack ();
201                 
202                 public XPathNodeIterator CurrentNodeset {
203                         get { return (XPathNodeIterator)nodesetStack.Peek (); }
204                 }
205                 
206                 public XPathNavigator CurrentNode {
207                         get { return CurrentNodeset.Current; }
208                 }
209                 
210                 public bool NodesetMoveNext ()
211                 {
212                         return CurrentNodeset.MoveNext ();
213                 }
214                 
215                 public void PushNodeset (XPathNodeIterator itr)
216                 {
217                         nodesetStack.Push (itr.Clone ());
218                 }
219                 
220                 public void PopNodeset ()
221                 {
222                         nodesetStack.Pop ();
223                 }
224                 #endregion
225                 
226                 #region Evaluate
227                 public object Evaluate (XPathExpression expr)
228                 {
229                         expr = CompiledStyle.ExpressionStore.PrepForExecution (expr, this);
230                         
231                         XPathNodeIterator itr = CurrentNodeset;
232                         return itr.Current.Evaluate (expr, itr);
233                 }
234                 
235                 public string EvaluateString (XPathExpression expr)
236                 {
237                         expr = CompiledStyle.ExpressionStore.PrepForExecution (expr, this);
238                         
239                         XPathNodeIterator itr = CurrentNodeset;
240                         return itr.Current.EvaluateString (expr, itr);
241                 }
242                                 
243                 public bool EvaluateBoolean (XPathExpression expr)
244                 {
245                         expr = CompiledStyle.ExpressionStore.PrepForExecution (expr, this);
246                         
247                         XPathNodeIterator itr = CurrentNodeset;
248                         return itr.Current.EvaluateBoolean (expr, itr);
249                 }
250                 
251                 public XPathNodeIterator Select (XPathExpression expr)
252                 {
253                         expr = CompiledStyle.ExpressionStore.PrepForExecution (expr, this);
254                         return CurrentNodeset.Current.Select (expr);
255                 }
256                 
257                 #endregion
258                 
259                 public XslAttributeSet ResolveAttributeSet (QName name)
260                 {
261                         return CompiledStyle.ResolveAttributeSet (name);
262                 }
263                 
264                 #region Variable Stack
265                 Stack variableStack = new Stack ();
266                 object [] currentStack;
267                 
268                 public object GetStackItem (int slot)
269                 {
270                         return currentStack [slot];
271                 }
272                 
273                 public void SetStackItem (int slot, object o)
274                 {
275                         currentStack [slot] = o;
276                 }
277                 
278                 public void PushStack (int stackSize)
279                 {
280                         variableStack.Push (currentStack);
281                         currentStack = new object [stackSize];
282                 }
283                 
284                 public void PopStack ()
285                 {
286                         currentStack = (object[])variableStack.Pop();
287                 }
288                 
289                 #endregion
290                 
291         }
292 }