2006-02-21 Atsushi Enomoto <atsushi@ximian.com>
[mono.git] / mcs / class / System.XML / Mono.Xml.Xsl / XslOutput.cs
1 //
2 // XslOutput.cs
3 //
4 // Authors:
5 //      Ben Maurer (bmaurer@users.sourceforge.net)
6 //      Atsushi Enomoto (ginga@kit.hi-ho.ne.jp)
7 //      Oleg Tkachenko (oleg@tkachenko.com)
8 //      
9 // (C) 2003 Ben Maurer
10 // (C) 2003 Atsushi Enomoto
11 // (C) 2003 Oleg Tkachenko
12 //
13
14 //
15 // Permission is hereby granted, free of charge, to any person obtaining
16 // a copy of this software and associated documentation files (the
17 // "Software"), to deal in the Software without restriction, including
18 // without limitation the rights to use, copy, modify, merge, publish,
19 // distribute, sublicense, and/or sell copies of the Software, and to
20 // permit persons to whom the Software is furnished to do so, subject to
21 // the following conditions:
22 // 
23 // The above copyright notice and this permission notice shall be
24 // included in all copies or substantial portions of the Software.
25 // 
26 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
27 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
28 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
29 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
30 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
31 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
32 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
33 //
34
35 using System;
36 using System.Collections;
37 using System.Xml;
38 using System.Xml.Schema;
39 using System.Xml.XPath;
40 using System.Xml.Xsl;
41 using System.Text;
42
43 namespace Mono.Xml.Xsl
44 {
45         using QName = System.Xml.XmlQualifiedName;
46
47         internal enum OutputMethod {
48                 XML,
49                 HTML,
50                 Text,
51                 Custom,
52                 Unknown
53         }
54         
55         internal enum StandaloneType {
56                 NONE,
57                 YES,
58                 NO
59         }
60
61         internal class XslOutput // also usable for xsl:result-document
62         {
63                 string uri;
64                 QName customMethod;
65                 OutputMethod method = OutputMethod.Unknown; 
66                 string version;
67                 Encoding encoding = System.Text.Encoding.UTF8;
68                 bool omitXmlDeclaration;
69                 StandaloneType standalone = StandaloneType.NONE;
70                 string doctypePublic;
71                 string doctypeSystem;
72                 QName [] cdataSectionElements;
73                 string indent;
74                 string mediaType;
75                 string stylesheetVersion;
76
77                 // for compilation only.
78                 ArrayList cdSectsList = new ArrayList ();
79
80                 public XslOutput (string uri, string stylesheetVersion)
81                 {
82                         this.uri = uri;
83                         this.stylesheetVersion = stylesheetVersion;
84                 }
85
86                 public OutputMethod Method { get { return method; }}
87                 public QName CustomMethod { get { return customMethod; }}
88
89                 public string Version {
90                         get { return version; }
91                 }
92
93                 public Encoding Encoding {
94                         get { return encoding; }
95                 }
96
97                 public string Uri {
98                         get { return uri; }
99                 }
100
101                 public bool OmitXmlDeclaration {
102                         get { return omitXmlDeclaration; }
103                 }
104
105                 public StandaloneType Standalone {
106                         get { return standalone; }
107                 }
108
109                 public string DoctypePublic {
110                         get { return doctypePublic; }
111                 }
112
113                 public string DoctypeSystem {
114                         get { return doctypeSystem; }
115                 }
116
117                 public QName [] CDataSectionElements {
118                         get {
119                                 if (cdataSectionElements == null)
120                                         cdataSectionElements = cdSectsList.ToArray (typeof (QName)) as QName [];
121                                 return cdataSectionElements;
122                         }
123                 }
124
125                 public string Indent {
126                         get { return indent; }
127                 }
128
129                 public string MediaType {
130                         get { return mediaType; }
131                 }
132
133                 public void Fill (XPathNavigator nav)
134                 {
135                         if (nav.MoveToFirstAttribute ()) {
136                                 ProcessAttribute (nav);
137                                 while (nav.MoveToNextAttribute ()) {
138                                         ProcessAttribute (nav);
139                                 }
140
141                                 // move back to original position
142                                 nav.MoveToParent ();
143                         }
144                 }
145
146                 private void ProcessAttribute (XPathNavigator nav)
147                 {
148                         // skip attributes from non-default namespace
149                         if (nav.NamespaceURI != string.Empty) {
150                                 return;
151                         }
152
153                         string value = nav.Value;
154
155                         switch (nav.LocalName) {
156                         case "cdata-section-elements":
157                                 if (value.Length > 0) {
158                                         cdSectsList.AddRange (XslNameUtil.FromListString (value, nav));
159                                 }
160                                 break;
161                         case "method":
162                                 if (value.Length == 0) {
163                                         break;
164                                 }
165
166                                 switch (value) {
167                                         case "xml":
168                                                 method = OutputMethod.XML;
169                                                 break;
170                                         case "html":
171                                                 omitXmlDeclaration = true;
172                                                 method = OutputMethod.HTML;
173                                                 break;
174                                         case "text":
175                                                 omitXmlDeclaration = true;
176                                                 method = OutputMethod.Text;
177                                                 break;
178                                         default:
179                                                 method = OutputMethod.Custom;
180                                                 customMethod = XslNameUtil.FromString (value, nav);
181                                                 if (customMethod.Namespace == String.Empty) {
182                                                         IXmlLineInfo li = nav as IXmlLineInfo;
183                                                         throw new XsltCompileException (new ArgumentException (
184                                                                 "Invalid output method value: '" + value + "'. It" +
185                                                                 " must be either 'xml' or 'html' or 'text' or QName."),
186                                                                 nav.BaseURI,
187                                                                 li != null ? li.LineNumber : 0,
188                                                                 li != null ? li.LinePosition : 0);
189                                                 }
190                                                 break;
191                                 }
192                                 break;
193                         case "version":
194                                 if (value.Length > 0) {
195                                         this.version = value;
196                                 }
197                                 break;
198                         case "encoding":
199                                 if (value.Length > 0) {
200                                         try {
201                                                 this.encoding = System.Text.Encoding.GetEncoding (value);
202                                         } catch (ArgumentException) {
203                                                 // MS.NET just leaves the default encoding when encoding is unknown
204                                         } catch (NotSupportedException) {
205                                                 // Workaround for a bug in System.Text, it throws invalid exception
206                                         }
207                                 }
208                                 break;
209                         case "standalone":
210                                 switch (value) {
211                                         case "yes":
212                                                 this.standalone = StandaloneType.YES;
213                                                 break;
214                                         case "no":
215                                                 this.standalone = StandaloneType.NO;
216                                                 break;
217                                         default:
218                                                 if (stylesheetVersion != "1.0")
219                                                         break;
220
221                                                 IXmlLineInfo li = nav as IXmlLineInfo;
222                                                 throw new XsltCompileException (new XsltException (
223                                                         "'" + value + "' is an invalid value for 'standalone'" +
224                                                         " attribute.", (Exception) null),
225                                                         nav.BaseURI,
226                                                         li != null ? li.LineNumber : 0,
227                                                         li != null ? li.LinePosition : 0);
228                                 }
229                                 break;
230                         case "doctype-public":
231                                 this.doctypePublic = value;
232                                 break;
233                         case "doctype-system":
234                                 this.doctypeSystem = value;
235                                 break;
236                         case "media-type":
237                                 if (value.Length > 0) {
238                                         this.mediaType = value;
239                                 }
240                                 break;
241                         case "omit-xml-declaration":
242                                 switch (value) {
243                                         case "yes":
244                                                 this.omitXmlDeclaration = true;
245                                                 break;
246                                         case "no":
247                                                 this.omitXmlDeclaration = false;
248                                                 break;
249                                         default:
250                                                 if (stylesheetVersion != "1.0")
251                                                         break;
252
253                                                 IXmlLineInfo li = nav as IXmlLineInfo;
254                                                 throw new XsltCompileException (new XsltException (
255                                                         "'" + value + "' is an invalid value for 'omit-xml-declaration'" +
256                                                         " attribute.", (Exception) null),
257                                                         nav.BaseURI,
258                                                         li != null ? li.LineNumber : 0,
259                                                         li != null ? li.LinePosition : 0);
260                                 }
261                                 break;
262                         case "indent":
263                                 indent = value;
264                                 if (stylesheetVersion != "1.0")
265                                         break;
266                                 switch (value) {
267                                 case "yes":
268                                 case "no":
269                                         break;
270                                 default:
271                                         switch (method) {
272                                         case OutputMethod.Custom:
273                                                 break;
274                                         default:
275                                                 IXmlLineInfo li = nav as IXmlLineInfo;
276                                                 throw new XsltCompileException (String.Format ("Unexpected 'indent' attribute value in 'output' element: '{0}'", value), null, nav);
277                                         }
278                                         break;
279                                 }
280                                 break;
281                         default:
282                                 if (stylesheetVersion != "1.0")
283                                         break;
284
285                                 IXmlLineInfo li = nav as IXmlLineInfo;
286                                 throw new XsltCompileException (new XsltException (
287                                         "'" + nav.LocalName + "' is an invalid attribute for 'output'" +
288                                         " element.", (Exception) null),
289                                         nav.BaseURI,
290                                         li != null ? li.LineNumber : 0,
291                                         li != null ? li.LinePosition : 0);
292                         }
293                 }
294         }
295 }