more executable bits
[mono.git] / mcs / class / Commons.Xml.Relaxng / Commons.Xml.Relaxng.Rnc / RncWriter.cs
1 //\r
2 // RELAX NG Compact Syntax writer\r
3 //\r
4 // Author:\r
5 //      Atsushi Enomoto <atsushi@ximian.com>\r
6 //\r
7 // (C)2005 Novell Inc.\r
8 //\r
9
10 //
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
18 // 
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
21 // 
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 //
30 \r
31 using System;\r
32 using System.Collections;\r
33 using System.IO;\r
34 using System.Xml;\r
35 using Commons.Xml.Relaxng;\r
36 \r
37 #if NET_2_0\r
38 using NSResolver = System.Xml.IXmlNamespaceResolver;\r
39 #else\r
40 using NSResolver = System.Xml.XmlNamespaceManager;\r
41 #endif\r
42 \r
43 namespace Commons.Xml.Relaxng.Rnc\r
44 {\r
45         internal class RncWriter\r
46         {\r
47                 static readonly XmlNamespaceManager defaultNamespaceManager;\r
48 \r
49                 static RncWriter ()\r
50                 {\r
51                         XmlNamespaceManager n = new XmlNamespaceManager (\r
52                                 new NameTable ());\r
53                         n.AddNamespace ("xs", "http://www.w3.org/2001/XMLSchema-datatypes");\r
54                         n.AddNamespace ("xsi", "http://www.w3.org/2001/XMLSchema-instance");\r
55                         defaultNamespaceManager = n;\r
56                 }\r
57 \r
58                 TextWriter w;\r
59                 NSResolver nsmgr;\r
60 \r
61                 public RncWriter (TextWriter writer)\r
62                         : this (writer, defaultNamespaceManager)\r
63                 {\r
64                 }\r
65 \r
66                 public RncWriter (TextWriter writer, NSResolver nsmgr)\r
67                 {\r
68                         this.w = writer;\r
69                         this.nsmgr = nsmgr;\r
70                 }\r
71 \r
72                 #region Utility methods\r
73 \r
74                 private void WriteNames (RelaxngNameClassList l, bool wrap)\r
75                 {\r
76                         switch (l.Count) {\r
77                         case 0:\r
78                                 throw new RelaxngException ("name choice must contain at least one name class.");\r
79                         case 1:\r
80                                 l [0].WriteRnc (this);\r
81                                 break;\r
82                         default:\r
83                                 if (wrap)\r
84                                         w.Write ('(');\r
85                                 l [0].WriteRnc (this);\r
86                                 for (int i = 1; i < l.Count; i++) {\r
87                                         w.Write ('|');\r
88                                         l [i].WriteRnc (this);\r
89                                 }\r
90                                 if (wrap)\r
91                                         w.Write (')');\r
92                                 break;\r
93                         }\r
94                 }\r
95 \r
96                 private void WritePatterns (RelaxngPatternList l, bool parens)\r
97                 {\r
98                         WritePatterns (l, ',', parens);\r
99                 }\r
100 \r
101                 private void WritePatterns (RelaxngPatternList l,\r
102                         char sep, bool parens)\r
103                 {\r
104                         switch (l.Count) {\r
105                         case 0:\r
106                                 w.Write ("empty");\r
107                                 break;\r
108                         case 1:\r
109                                 parens = (l [0] is RelaxngBinaryContentPattern \r
110                                         || l [0] is RelaxngData && ((RelaxngData) l [0]).Except != null);\r
111                                 if (parens)\r
112                                         w.Write ('(');\r
113                                 l [0].WriteRnc (this);\r
114                                 if (parens)\r
115                                         w.Write (')');\r
116                                 break;\r
117                         default:\r
118                                 if (parens)\r
119                                         w.Write ('(');\r
120                                 l [0].WriteRnc (this);\r
121                                 for (int i = 1; i < l.Count; i++) {\r
122                                         if (sep != ',')\r
123                                                 w.Write (' ');\r
124                                         w.Write (sep);\r
125                                         w.Write (' ');\r
126                                         l [i].WriteRnc (this);\r
127                                 }\r
128                                 if (parens)\r
129                                         w.Write (')');\r
130                                 break;\r
131                         }\r
132                 }\r
133 \r
134                 private void WriteGrammarIncludeContents (\r
135                         RelaxngGrammarContentList starts,\r
136                         RelaxngGrammarContentList defines,\r
137                         RelaxngGrammarContentList divs,\r
138                         RelaxngGrammarContentList includes)\r
139                 {\r
140                         if (includes != null)\r
141                                 foreach (RelaxngInclude inc in includes)\r
142                                         inc.WriteRnc (this);\r
143                         if (divs != null)\r
144                                 foreach (RelaxngDiv div in divs)\r
145                                         div.WriteRnc (this);\r
146                         if (starts != null)\r
147                                 foreach (RelaxngStart s in starts)\r
148                                         s.WriteRnc (this);\r
149                         if (defines != null)\r
150                                 foreach (RelaxngDefine def in defines)\r
151                                         def.WriteRnc (this);\r
152                 }\r
153 \r
154                 private void WriteQName (string name, string ns)\r
155                 {\r
156                         string prefix = String.Empty;\r
157                         if (ns != null && ns != String.Empty) {\r
158 #if NET_2_0\r
159 #else\r
160                                 // XmlNamespaceManager sucks.\r
161                                 ns = nsmgr.NameTable.Add (ns);\r
162 #endif\r
163                                 prefix = nsmgr.LookupPrefix (ns);\r
164                         }\r
165                         if (prefix == null)\r
166                                 throw new RelaxngException (String.Format ("Namespace '{0}' is not mapped to a prefix in argument XmlNamespaceManager.", ns));\r
167                         if (prefix != String.Empty) {\r
168                                 w.Write (prefix);\r
169                                 w.Write (':');\r
170                         }\r
171                         w.Write (name);\r
172                 }\r
173 \r
174                 private void WriteLiteral (string value)\r
175                 {\r
176                         w.Write ('"');\r
177                         for (int i = 0; i < value.Length; i++) {\r
178                                 switch (value [i]) {\r
179                                 case '"':\r
180                                         w.Write ("\\x{22}");\r
181                                         break;\r
182                                 case '\r':\r
183                                         w.Write ("\\x{13}");\r
184                                         break;\r
185                                 case '\n':\r
186                                         w.Write ("\\x{10}");\r
187                                         break;\r
188                                 case '\t': // It is not required, but would be better.\r
189                                         w.Write ("\\x{9}");\r
190                                         break;\r
191                                 default:\r
192                                         w.Write (value [i]);\r
193                                         break;\r
194                                 }\r
195                         }\r
196                         w.Write ('"');\r
197                 }\r
198 \r
199                 #endregion\r
200 \r
201                 #region Elements\r
202                 // Note that it might not be used directly when a grammar\r
203                 // contains more than one "start" (compact syntax does not\r
204                 // support "combine" attribute).\r
205                 public void WriteStart (RelaxngStart start)\r
206                 {\r
207                         w.Write ("start");\r
208                         if (start.Combine == null)\r
209                                 w.Write (" = ");\r
210                         else\r
211                                 w.Write (start.Combine.Trim () == "interleave" ?\r
212                                         " &= " : " |= ");\r
213                         start.Pattern.WriteRnc (this);\r
214                         w.WriteLine ();\r
215                 }\r
216 \r
217                 // Note that it might not be used directly when a grammar\r
218                 // contains more than one "define" for an identical name\r
219                 // (compact syntax does not support "combine" attribute).\r
220                 public void WriteDefine (RelaxngDefine define)\r
221                 {\r
222                         w.Write (define.Name);\r
223                         if (define.Combine == null)\r
224                                 w.Write (" = ");\r
225                         else\r
226                                 w.Write (define.Combine.Trim () == "interleave" ?\r
227                                         " &= " : " |= ");\r
228                         if (define.Patterns.Count == 0)\r
229                                 w.Write ("empty");\r
230                         else {\r
231                                 define.Patterns [0].WriteRnc (this);\r
232                                 for (int i = 1; i < define.Patterns.Count; i++) {\r
233                                         w.Write (",");\r
234                                         define.Patterns [i].WriteRnc (this);\r
235                                 }\r
236                         }\r
237                         w.WriteLine ();\r
238                 }\r
239 \r
240                 public void WriteInclude (RelaxngInclude include)\r
241                 {\r
242                         w.Write ("include ");\r
243                         w.Write (include.Href);\r
244 \r
245                         // FIXME: optInherit?\r
246 \r
247                         if (include.Starts.Count > 0 ||\r
248                                 include.Defines.Count > 0 ||\r
249                                 include.Divs.Count > 0) {\r
250                                 w.Write ('(');\r
251                                 WriteGrammarIncludeContents (include.Starts,\r
252                                         include.Defines, include.Divs, null);\r
253                                 w.Write (')');\r
254                         }\r
255                         w.WriteLine ();\r
256                 }\r
257 \r
258                 public void WriteDiv (RelaxngDiv div)\r
259                 {\r
260                         w.Write ("div { ");\r
261                         WriteGrammarIncludeContents (div.Starts,\r
262                                 div.Defines, div.Divs, div.Includes);\r
263                         w.WriteLine ('}');\r
264                 }\r
265 \r
266                 public void WriteNotAllowed (RelaxngNotAllowed na)\r
267                 {\r
268                         w.Write ("notAllowed ");\r
269                 }\r
270 \r
271                 public void WriteEmpty (RelaxngEmpty empty)\r
272                 {\r
273                         w.Write ("empty ");\r
274                 }\r
275 \r
276                 public void WriteText (RelaxngText text)\r
277                 {\r
278                         w.Write ("text ");\r
279                 }\r
280 \r
281                 public void WriteData (RelaxngData data)\r
282                 {\r
283                         WriteQName (data.Type, data.DatatypeLibrary);\r
284                         if (data.ParamList.Count > 0) {\r
285                                 w.Write (" { ");\r
286                                 foreach (RelaxngParam p in data.ParamList)\r
287                                         p.WriteRnc (this);\r
288                                 w.Write (" }");\r
289                         }\r
290                         if (data.Except != null)\r
291                                 data.Except.WriteRnc (this);\r
292                 }\r
293 \r
294                 public void WriteValue (RelaxngValue v)\r
295                 {\r
296                         WriteQName (v.Type, v.DatatypeLibrary);\r
297                         w.Write (' ');\r
298                         WriteLiteral (v.Value);\r
299                 }\r
300 \r
301                 public void WriteList (RelaxngList p)\r
302                 {\r
303                         w.Write ("list {");\r
304                         WritePatterns (p.Patterns, false);\r
305                         w.Write ("}");\r
306                 }\r
307 \r
308                 public void WriteMixed (RelaxngMixed p)\r
309                 {\r
310                         w.Write ("mixed {");\r
311                         WritePatterns (p.Patterns, false);\r
312                         w.Write ("}");\r
313                 }\r
314 \r
315                 public void WriteElement (RelaxngElement element)\r
316                 {\r
317                         w.Write ("element ");\r
318                         element.NameClass.WriteRnc (this);\r
319                         w.Write (" {");\r
320                         WritePatterns (element.Patterns, false);\r
321                         w.Write ("}");\r
322                 }\r
323 \r
324                 public void WriteAttribute (RelaxngAttribute attribute)\r
325                 {\r
326                         w.Write ("attribute ");\r
327                         attribute.NameClass.WriteRnc (this);\r
328                         w.Write (" {");\r
329                         if (attribute.Pattern == null)\r
330                                 w.Write ("empty");\r
331                         else\r
332                                 attribute.Pattern.WriteRnc (this);\r
333                         w.Write (" }");\r
334                 }\r
335 \r
336                 public void WriteRef (RelaxngRef r)\r
337                 {\r
338                         w.Write (r.Name);\r
339                 }\r
340 \r
341                 public void WriteParentRef (RelaxngParentRef r)\r
342                 {\r
343                         w.Write ("parent ");\r
344                         w.Write (r.Name);\r
345                         w.Write (' ');\r
346                 }\r
347 \r
348                 public void WriteExternalRef (RelaxngExternalRef r)\r
349                 {\r
350                         w.Write ("external ");\r
351                         w.Write (r.Href);\r
352                         // FIXME: optInherit?\r
353                         w.Write (' ');\r
354                 }\r
355 \r
356                 public void WriteOneOrMore (RelaxngOneOrMore p)\r
357                 {\r
358                         WritePatterns (p.Patterns, true);\r
359                         w.Write ('+');\r
360                 }\r
361 \r
362                 public void WriteZeroOrMore (RelaxngZeroOrMore p)\r
363                 {\r
364                         WritePatterns (p.Patterns, true);\r
365                         w.Write ('*');\r
366                 }\r
367 \r
368                 public void WriteOptional (RelaxngOptional p)\r
369                 {\r
370                         WritePatterns (p.Patterns, true);\r
371                         w.Write ('?');\r
372                 }\r
373 \r
374                 public void WriteChoice (RelaxngChoice p)\r
375                 {\r
376                         WritePatterns (p.Patterns, '|', false);\r
377                 }\r
378 \r
379                 public void WriteGroup (RelaxngGroup p)\r
380                 {\r
381                         WritePatterns (p.Patterns, ',', false);\r
382                 }\r
383 \r
384                 public void WriteInterleave (RelaxngInterleave p)\r
385                 {\r
386                         WritePatterns (p.Patterns, '&', false);\r
387                 }\r
388 \r
389                 public void WriteParam (RelaxngParam p)\r
390                 {\r
391                         w.Write (p.Name);\r
392                         w.Write (" = ");\r
393                         WriteLiteral (p.Value);\r
394                 }\r
395 \r
396                 public void WriteDataExcept (RelaxngExcept e)\r
397                 {\r
398                         w.Write (" - ");\r
399                         WritePatterns (e.Patterns, true);\r
400                 }\r
401 \r
402                 public void WriteGrammar (RelaxngGrammar g)\r
403                 {\r
404                         w.WriteLine ("grammar {");\r
405                         WriteGrammarIncludeContents (g.Starts,\r
406                                 g.Defines, g.Divs, g.Includes);\r
407                         w.WriteLine ('}');\r
408                 }\r
409 \r
410                 public void WriteAnyName (RelaxngAnyName n)\r
411                 {\r
412                         w.Write ('*');\r
413                         if (n.Except != null)\r
414                                 n.Except.WriteRnc (this);\r
415                 }\r
416 \r
417                 public void WriteNsName (RelaxngNsName n)\r
418                 {\r
419                         WriteQName ("*", n.Namespace);\r
420                         if (n.Except != null)\r
421                                 n.Except.WriteRnc (this);\r
422                 }\r
423 \r
424                 public void WriteName (RelaxngName n)\r
425                 {\r
426                         WriteQName (n.LocalName, n.Namespace);\r
427                 }\r
428 \r
429                 public void WriteNameChoice (RelaxngNameChoice c)\r
430                 {\r
431                         WriteNames (c.Children, false);\r
432                 }\r
433 \r
434                 public void WriteNameExcept (RelaxngExceptNameClass e)\r
435                 {\r
436                         w.Write (" - ");\r
437                         WriteNames (e.Names, true);\r
438                 }\r
439                 #endregion\r
440         }\r
441 }