2003-11-19 Atsushi Enomoto <ginga@kit.hi-ho.ne.jp>
[mono.git] / mcs / class / System.XML / Mono.Xml.Xsl / XslStylesheet.cs
1 //
2 // XslStylesheet.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.CodeDom;
14 using System.Collections;
15 using System.Collections.Specialized;
16 using System.Xml;
17 using System.Xml.Schema;
18 using System.Xml.XPath;
19 using System.Xml.Xsl;
20 using System.IO;
21
22 using Mono.Xml.Xsl.Operations;
23
24 using QName = System.Xml.XmlQualifiedName;
25
26 namespace Mono.Xml.Xsl {
27
28         public class XslStylesheet {
29                 public const string XsltNamespace = "http://www.w3.org/1999/XSL/Transform";
30                 public const string MSXsltNamespace = "urn:schemas-microsoft-com:xslt::script";
31                 
32                 Compiler c;
33
34                 XslStylesheet importer;
35                 // Top-level elements
36                 ArrayList imports = new ArrayList ();
37                 // [QName]=>XmlSpace
38                 Hashtable spaceControls = new Hashtable ();
39                 // [string stylesheet-prefix]=>string result-prefix
40                 Hashtable namespaceAliases = new Hashtable ();
41                 // [QName]=>XmlSpace
42                 Hashtable parameters = new Hashtable ();
43                 // [QName]=>XslKey
44                 Hashtable keys = new Hashtable();
45
46                 MSXslScriptManager msScripts = new MSXslScriptManager ();
47                 XslTemplateTable templates;
48
49                 // stylesheet attributes
50                 string version;
51                 XmlQualifiedName [] extensionElementPrefixes;
52                 XmlQualifiedName [] excludeResultPrefixes;
53                 StringDictionary stylesheetNamespaces = new StringDictionary ();
54
55                 // below are newly introduced in XSLT 2.0
56                 //  elements::
57                 // xsl:import-schema should be interpreted into it.
58                 XmlSchemaCollection schemas = new XmlSchemaCollection ();
59                 // [QName]=>XslCharacterMap
60                 Hashtable characterMap = new Hashtable ();
61                 // [QName]=>XslDateFormat
62                 Hashtable dateFormats = new Hashtable ();
63                 // [QName]=>XslFunction
64                 Hashtable functions = new Hashtable ();
65                 // [QName]=>XslSortKey
66                 Hashtable sortKeys = new Hashtable ();
67                 //  attributes::
68                 string xpathDefaultNamespace = "";
69                 XslDefaultValidation defaultValidation = XslDefaultValidation.Lax;
70
71                 public XmlQualifiedName [] ExtensionElementPrefixes {
72                         get { return extensionElementPrefixes; }
73                 }
74
75                 public XmlQualifiedName [] ExcludeResultPrefixes {
76                         get { return excludeResultPrefixes; }
77                 }
78
79                 public StringDictionary StylesheetNamespaces {
80                         get { return stylesheetNamespaces; }
81                 }
82
83                 public ArrayList Imports {
84                         get { return imports; }
85                 }
86
87                 public Hashtable SpaceControls {
88                         get { return spaceControls; }
89                 }
90
91                 public Hashtable NamespaceAliases {
92                         get { return namespaceAliases; }
93                 }
94
95                 public Hashtable Parameters {
96                         get { return parameters; }
97                 }
98
99                 public MSXslScriptManager ScriptManager{
100                         get { return msScripts; }
101                 }
102
103                 public XslTemplateTable Templates {
104                         get { return templates; }
105                 }
106
107                 public Hashtable Keys {
108                         get { return keys; }
109                 }
110
111                 public XslStylesheet (Compiler c)
112                 {
113                         this.c = c;
114                         c.PushStylesheet (this);
115                         
116                         templates = new XslTemplateTable (this);
117                         if (c.Input.NamespaceURI != XsltNamespace) {
118                                 // then it is simplified stylesheet.
119                                 Templates.Add (new XslTemplate (c));
120                         } else {
121                                 version = c.Input.GetAttribute ("version", "");
122                                 extensionElementPrefixes = c.ParseQNameListAttribute ("extension-element-prefixes");
123                                 excludeResultPrefixes = c.ParseQNameListAttribute ("exclude-result-prefixes");
124                                 if (c.Input.MoveToFirstNamespace (XPathNamespaceScope.Local)) {
125                                         do {
126                                                 if (c.Input.Value == XsltNamespace)
127                                                         continue;
128                                                 this.stylesheetNamespaces.Add (c.Input.Name, c.Input.Value);
129                                         } while (c.Input.MoveToNextNamespace (XPathNamespaceScope.Local));
130                                         c.Input.MoveToParent ();
131                                 }
132                                 ProcessTopLevelElements ();
133                         }
134                         
135                         c.PopStylesheet ();
136                 }
137                 
138                 public XslKey FindKey (QName name)
139                 {
140                         XslKey key = Keys [name] as XslKey;
141                         if (key != null)
142                                 return key;
143                         for (int i = Imports.Count - 1; i >= 0; i--) {
144                                 key = ((XslStylesheet) Imports [i]).FindKey (name);
145                                 if (key != null)
146                                         return key;
147                         }
148                         return null;
149                 }
150
151                 private XslStylesheet (Compiler c, XslStylesheet importer) : this (c)
152                 {
153                         this.importer = importer;
154                 }
155                 
156                 private void HandleInclude (string href)
157                 {
158                         c.PushInputDocument (href);
159                         ProcessTopLevelElements ();
160                         c.PopInputDocument ();
161                 }
162                 
163                 private void HandleImport (string href)
164                 {
165                         c.PushInputDocument (href);
166                         imports.Add (new XslStylesheet (c, this));
167                         c.PopInputDocument ();
168                 }
169                 
170                 private void HandleTopLevelElement ()
171                 {
172                         XPathNavigator n = c.Input;
173                         switch (n.NamespaceURI)
174                         {
175                         case XsltNamespace:
176                                 
177                                 switch (n.LocalName)
178                                 {
179                                 case "include":
180                                         HandleInclude (c.GetAttribute ("href"));
181                                         break;
182                                 case "import":
183                                         HandleImport (c.GetAttribute ("href"));
184                                         break;
185                                 case "preserve-space":
186                                         AddSpaceControls (c.ParseQNameListAttribute ("elements"), XmlSpace.Preserve, n);
187                                         break;
188                                 
189                                 case "strip-space":
190                                         AddSpaceControls (c.ParseQNameListAttribute ("elements"), XmlSpace.Default, n);
191                                         break;
192                                 
193                                 case "namespace-alias":
194                                         namespaceAliases.Add (c.GetAttribute ("stylesheet-prefix", ""), c.GetAttribute ("result-prefix", ""));
195                                         break;
196                                 
197                                 case "attribute-set":
198                                         c.AddAttributeSet (new XslAttributeSet (c));
199                                         break;
200
201                                 case "key":
202                                         keys.Add (c.ParseQNameAttribute ("name"), new XslKey (c));
203                                         break;
204                                         
205                                 case "output":
206                                         c.CompileOutput ();
207                                         break;
208                                 
209                                 case "decimal-format":
210                                         c.CompileDecimalFormat ();
211                                         break;
212                                         
213                                 case "template":
214                                         templates.Add (new XslTemplate (c));    
215                                         break;
216                                 case "variable":
217                                         c.AddGlobalVariable (new XslGlobalVariable (c));
218                                         break;
219                                 case "param":
220                                         c.AddGlobalVariable (new XslGlobalParam (c));
221                                         break;
222                                 }
223                                 break;
224                         case MSXsltNamespace:
225                                 switch (n.LocalName)
226                                 {
227                                 case "script":
228                                         msScripts.AddScript (n);
229                                         break;
230                                 }
231                                 break;
232                         }
233                 }
234                 
235                 private void ProcessTopLevelElements ()
236                 {
237                         if (c.Input.MoveToFirstChild ()) {
238                                 do {
239                                         if (c.Input.NodeType == XPathNodeType.Element) {                                        
240                                                 Debug.EnterNavigator (c);
241                                                 this.HandleTopLevelElement();
242                                                 Debug.ExitNavigator (c);
243                                         }
244                                 } while (c.Input.MoveToNext ());
245                                 
246                                 c.Input.MoveToParent ();
247                         }
248                 }
249
250                 private void AddSpaceControls (QName [] names, XmlSpace result, XPathNavigator styleElem)
251                 {
252                         foreach (QName name in names)
253                                 spaceControls.Add (name, result);
254                 }
255
256         }
257
258         
259         public enum XslDefaultValidation
260         {
261                 Strict,
262                 Lax,
263                 Preserve,
264                 Strip
265         }
266 }