2 // RELAX NG Compact Syntax writer
\r
5 // Atsushi Enomoto <atsushi@ximian.com>
\r
7 // (C)2005 Novell Inc.
\r
11 // Permission is hereby granted, free of charge, to any person obtaining
\r
12 // a copy of this software and associated documentation files (the
\r
13 // "Software"), to deal in the Software without restriction, including
\r
14 // without limitation the rights to use, copy, modify, merge, publish,
\r
15 // distribute, sublicense, and/or sell copies of the Software, and to
\r
16 // permit persons to whom the Software is furnished to do so, subject to
\r
17 // the following conditions:
\r
19 // The above copyright notice and this permission notice shall be
\r
20 // included in all copies or substantial portions of the Software.
\r
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
\r
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
\r
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
\r
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
\r
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
\r
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
\r
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\r
32 using System.Collections;
\r
35 using Commons.Xml.Relaxng;
\r
37 using NSResolver = System.Xml.IXmlNamespaceResolver;
\r
39 namespace Commons.Xml.Relaxng.Rnc
\r
41 internal class RncWriter
\r
43 static readonly XmlNamespaceManager defaultNamespaceManager;
\r
47 XmlNamespaceManager n = new XmlNamespaceManager (
\r
49 n.AddNamespace ("xs", "http://www.w3.org/2001/XMLSchema-datatypes");
\r
50 defaultNamespaceManager = n;
\r
55 NSResolver datansmgr;
\r
57 public RncWriter (TextWriter writer)
\r
58 : this (writer, null, defaultNamespaceManager)
\r
62 public RncWriter (TextWriter writer, NSResolver nsmgr)
\r
63 : this (writer, nsmgr, defaultNamespaceManager)
\r
67 public RncWriter (TextWriter writer, NSResolver structureNamespaces, NSResolver dataNamespaces)
\r
70 this.nsmgr = structureNamespaces;
\r
71 this.datansmgr = dataNamespaces;
\r
72 XmlNameTable nt = GetNameTable (nsmgr, datansmgr);
\r
74 nsmgr = new XmlNamespaceManager (nt);
\r
75 if (datansmgr == null)
\r
76 datansmgr = new XmlNamespaceManager (nt);
\r
79 #region Utility methods
\r
81 private XmlNameTable GetNameTable (NSResolver nss1, NSResolver nss2)
\r
83 XmlNameTable nt = null;
\r
84 if (nss1 is XmlNamespaceManager)
\r
85 nt = ((XmlNamespaceManager) nss1).NameTable;
\r
86 if (nss2 is XmlNamespaceManager)
\r
87 nt = ((XmlNamespaceManager) nss2).NameTable;
\r
89 nt = new NameTable ();
\r
93 private bool IsKeyword (string name)
\r
121 private void WriteNames (RelaxngNameClassList l, bool wrap)
\r
125 throw new RelaxngException ("name choice must contain at least one name class.");
\r
127 l [0].WriteRnc (this);
\r
132 l [0].WriteRnc (this);
\r
133 for (int i = 1; i < l.Count; i++) {
\r
135 l [i].WriteRnc (this);
\r
143 private void WritePatterns (RelaxngPatternList l, bool parens)
\r
145 WritePatterns (l, ',', parens);
\r
148 private void WritePatterns (RelaxngPatternList l,
\r
149 char sep, bool parens)
\r
156 parens = (l [0] is RelaxngBinaryContentPattern
\r
157 || l [0] is RelaxngData && ((RelaxngData) l [0]).Except != null);
\r
160 l [0].WriteRnc (this);
\r
167 l [0].WriteRnc (this);
\r
168 for (int i = 1; i < l.Count; i++) {
\r
173 l [i].WriteRnc (this);
\r
181 private void WriteGrammarIncludeContents (
\r
182 RelaxngGrammarContentList starts,
\r
183 RelaxngGrammarContentList defines,
\r
184 RelaxngGrammarContentList divs,
\r
185 RelaxngGrammarContentList includes)
\r
187 if (includes != null) {
\r
188 foreach (RelaxngInclude inc in includes)
\r
189 inc.WriteRnc (this);
\r
192 if (divs != null) {
\r
193 foreach (RelaxngDiv div in divs)
\r
194 div.WriteRnc (this);
\r
197 if (starts != null) {
\r
198 foreach (RelaxngStart s in starts)
\r
202 if (defines != null)
\r
203 foreach (RelaxngDefine def in defines)
\r
204 def.WriteRnc (this);
\r
207 private void WriteQName (string name, string ns)
\r
209 WriteQName (name, ns, nsmgr);
\r
212 private void WriteQName (string name, string ns, NSResolver nss)
\r
214 string prefix = String.Empty;
\r
215 if (ns != null && ns != String.Empty) {
\r
216 prefix = nss.LookupPrefix (ns);
\r
218 if (prefix == null)
\r
219 throw new RelaxngException (String.Format ("Namespace '{0}' is not mapped to a prefix in argument XmlNamespaceManager.", ns));
\r
220 if (prefix != String.Empty) {
\r
224 if (IsKeyword (name))
\r
229 private void WriteLiteral (string value)
\r
232 for (int i = 0; i < value.Length; i++) {
\r
233 switch (value [i]) {
\r
235 w.Write ("\\x{22}");
\r
238 w.Write ("\\x{13}");
\r
241 w.Write ("\\x{10}");
\r
243 case '\t': // It is not required, but would be better.
\r
244 w.Write ("\\x{9}");
\r
247 w.Write (value [i]);
\r
256 public void WriteNamespaces (string defaultNamespace)
\r
258 WriteNamespaces (defaultNamespace, nsmgr, false);
\r
259 WriteNamespaces (null, datansmgr, true);
\r
262 public void WriteNamespaces (string defaultNamespace, NSResolver nsmgr, bool isData)
\r
264 if (defaultNamespace == null)
\r
265 defaultNamespace = String.Empty;
\r
267 if (defaultNamespace.Length > 0)
\r
268 w.WriteLine ("default namespace = {0}",
\r
271 if (nsmgr != null) {
\r
272 foreach (string s in nsmgr.GetNamespacesInScope (
\r
273 XmlNamespaceScope.All).Keys) {
\r
279 if (defaultNamespace.Length > 0)
\r
280 w.WriteLine ("default namespace = '{0}'",
\r
281 nsmgr.LookupNamespace (s).Replace ('\'', '\"'));
\r
284 w.WriteLine ("{2} {0} = '{1}'",
\r
286 nsmgr.LookupNamespace (s).Replace ('\'', '\"'),
\r
287 isData ? "datatypes" : "namespace");
\r
296 // Note that it might not be used directly when a grammar
\r
297 // contains more than one "start" (compact syntax does not
\r
298 // support "combine" attribute).
\r
299 public void WriteStart (RelaxngStart start)
\r
302 if (start.Combine == null)
\r
305 w.Write (start.Combine.Trim () == "interleave" ?
\r
307 start.Pattern.WriteRnc (this);
\r
311 // Note that it might not be used directly when a grammar
\r
312 // contains more than one "define" for an identical name
\r
313 // (compact syntax does not support "combine" attribute).
\r
314 public void WriteDefine (RelaxngDefine define)
\r
316 if (IsKeyword (define.Name))
\r
318 w.Write (define.Name);
\r
319 if (define.Combine == null)
\r
322 w.Write (define.Combine.Trim () == "interleave" ?
\r
324 if (define.Patterns.Count == 0)
\r
327 define.Patterns [0].WriteRnc (this);
\r
328 for (int i = 1; i < define.Patterns.Count; i++) {
\r
330 define.Patterns [i].WriteRnc (this);
\r
337 public void WriteInclude (RelaxngInclude include)
\r
339 w.Write ("include ");
\r
340 w.Write (include.Href);
\r
342 // FIXME: optInherit?
\r
344 if (include.Starts.Count > 0 ||
\r
345 include.Defines.Count > 0 ||
\r
346 include.Divs.Count > 0) {
\r
348 WriteGrammarIncludeContents (include.Starts,
\r
349 include.Defines, include.Divs, null);
\r
355 public void WriteDiv (RelaxngDiv div)
\r
357 w.Write ("div { ");
\r
358 WriteGrammarIncludeContents (div.Starts,
\r
359 div.Defines, div.Divs, div.Includes);
\r
363 public void WriteNotAllowed (RelaxngNotAllowed na)
\r
365 w.Write ("notAllowed ");
\r
368 public void WriteEmpty (RelaxngEmpty empty)
\r
370 w.Write ("empty ");
\r
373 public void WriteText (RelaxngText text)
\r
378 public void WriteData (RelaxngData data)
\r
380 WriteQName (data.Type, data.DatatypeLibrary, datansmgr);
\r
381 if (data.ParamList.Count > 0) {
\r
383 foreach (RelaxngParam p in data.ParamList)
\r
387 if (data.Except != null)
\r
388 data.Except.WriteRnc (this);
\r
391 public void WriteValue (RelaxngValue v)
\r
393 WriteQName (v.Type, v.DatatypeLibrary, datansmgr);
\r
395 WriteLiteral (v.Value);
\r
398 public void WriteList (RelaxngList p)
\r
400 w.Write ("list {");
\r
401 WritePatterns (p.Patterns, false);
\r
405 public void WriteMixed (RelaxngMixed p)
\r
407 w.Write ("mixed {");
\r
408 WritePatterns (p.Patterns, false);
\r
412 public void WriteElement (RelaxngElement element)
\r
414 w.Write ("element ");
\r
415 element.NameClass.WriteRnc (this);
\r
417 WritePatterns (element.Patterns, false);
\r
421 public void WriteAttribute (RelaxngAttribute attribute)
\r
423 w.Write ("attribute ");
\r
424 attribute.NameClass.WriteRnc (this);
\r
426 if (attribute.Pattern == null)
\r
429 attribute.Pattern.WriteRnc (this);
\r
433 public void WriteRef (RelaxngRef r)
\r
435 if (IsKeyword (r.Name))
\r
440 public void WriteParentRef (RelaxngParentRef r)
\r
442 w.Write ("parent ");
\r
443 if (IsKeyword (r.Name))
\r
449 public void WriteExternalRef (RelaxngExternalRef r)
\r
451 w.Write ("external ");
\r
453 // FIXME: optInherit?
\r
457 public void WriteOneOrMore (RelaxngOneOrMore p)
\r
459 WritePatterns (p.Patterns, true);
\r
463 public void WriteZeroOrMore (RelaxngZeroOrMore p)
\r
465 WritePatterns (p.Patterns, true);
\r
469 public void WriteOptional (RelaxngOptional p)
\r
471 WritePatterns (p.Patterns, true);
\r
475 public void WriteChoice (RelaxngChoice p)
\r
477 WritePatterns (p.Patterns, '|', false);
\r
480 public void WriteGroup (RelaxngGroup p)
\r
482 WritePatterns (p.Patterns, ',', false);
\r
485 public void WriteInterleave (RelaxngInterleave p)
\r
487 WritePatterns (p.Patterns, '&', false);
\r
490 public void WriteParam (RelaxngParam p)
\r
492 if (IsKeyword (p.Name))
\r
496 WriteLiteral (p.Value);
\r
499 public void WriteDataExcept (RelaxngExcept e)
\r
502 WritePatterns (e.Patterns, true);
\r
505 public void WriteGrammar (RelaxngGrammar g)
\r
507 w.WriteLine ("grammar {");
\r
508 WriteGrammarIncludeContents (g.Starts,
\r
509 g.Defines, g.Divs, g.Includes);
\r
513 public void WriteAnyName (RelaxngAnyName n)
\r
516 if (n.Except != null)
\r
517 n.Except.WriteRnc (this);
\r
520 public void WriteNsName (RelaxngNsName n)
\r
522 WriteQName ("*", n.Namespace);
\r
523 if (n.Except != null)
\r
524 n.Except.WriteRnc (this);
\r
527 public void WriteName (RelaxngName n)
\r
529 WriteQName (n.LocalName, n.Namespace);
\r
532 public void WriteNameChoice (RelaxngNameChoice c)
\r
534 WriteNames (c.Children, false);
\r
537 public void WriteNameExcept (RelaxngExceptNameClass e)
\r
540 WriteNames (e.Names, true);
\r