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
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:
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
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.
32 using System.Collections;
\r
35 using Commons.Xml.Relaxng;
\r
38 using NSResolver = System.Xml.IXmlNamespaceResolver;
\r
40 using NSResolver = System.Xml.XmlNamespaceManager;
\r
43 namespace Commons.Xml.Relaxng.Rnc
\r
45 internal class RncWriter
\r
47 static readonly XmlNamespaceManager defaultNamespaceManager;
\r
51 XmlNamespaceManager n = new XmlNamespaceManager (
\r
53 n.AddNamespace ("xs", "http://www.w3.org/2001/XMLSchema-datatypes");
\r
54 defaultNamespaceManager = n;
\r
59 NSResolver datansmgr;
\r
61 public RncWriter (TextWriter writer)
\r
62 : this (writer, null, defaultNamespaceManager)
\r
66 public RncWriter (TextWriter writer, NSResolver nsmgr)
\r
67 : this (writer, nsmgr, defaultNamespaceManager)
\r
71 public RncWriter (TextWriter writer, NSResolver structureNamespaces, NSResolver dataNamespaces)
\r
74 this.nsmgr = structureNamespaces;
\r
75 this.datansmgr = dataNamespaces;
\r
76 XmlNameTable nt = GetNameTable (nsmgr, datansmgr);
\r
78 nsmgr = new XmlNamespaceManager (nt);
\r
79 if (datansmgr == null)
\r
80 datansmgr = new XmlNamespaceManager (nt);
\r
83 #region Utility methods
\r
85 private XmlNameTable GetNameTable (NSResolver nss1, NSResolver nss2)
\r
87 XmlNameTable nt = null;
\r
88 if (nss1 is XmlNamespaceManager)
\r
89 nt = ((XmlNamespaceManager) nss1).NameTable;
\r
90 if (nss2 is XmlNamespaceManager)
\r
91 nt = ((XmlNamespaceManager) nss2).NameTable;
\r
93 nt = new NameTable ();
\r
97 private bool IsKeyword (string name)
\r
125 private void WriteNames (RelaxngNameClassList l, bool wrap)
\r
129 throw new RelaxngException ("name choice must contain at least one name class.");
\r
131 l [0].WriteRnc (this);
\r
136 l [0].WriteRnc (this);
\r
137 for (int i = 1; i < l.Count; i++) {
\r
139 l [i].WriteRnc (this);
\r
147 private void WritePatterns (RelaxngPatternList l, bool parens)
\r
149 WritePatterns (l, ',', parens);
\r
152 private void WritePatterns (RelaxngPatternList l,
\r
153 char sep, bool parens)
\r
160 parens = (l [0] is RelaxngBinaryContentPattern
\r
161 || l [0] is RelaxngData && ((RelaxngData) l [0]).Except != null);
\r
164 l [0].WriteRnc (this);
\r
171 l [0].WriteRnc (this);
\r
172 for (int i = 1; i < l.Count; i++) {
\r
177 l [i].WriteRnc (this);
\r
185 private void WriteGrammarIncludeContents (
\r
186 RelaxngGrammarContentList starts,
\r
187 RelaxngGrammarContentList defines,
\r
188 RelaxngGrammarContentList divs,
\r
189 RelaxngGrammarContentList includes)
\r
191 if (includes != null) {
\r
192 foreach (RelaxngInclude inc in includes)
\r
193 inc.WriteRnc (this);
\r
196 if (divs != null) {
\r
197 foreach (RelaxngDiv div in divs)
\r
198 div.WriteRnc (this);
\r
201 if (starts != null) {
\r
202 foreach (RelaxngStart s in starts)
\r
206 if (defines != null)
\r
207 foreach (RelaxngDefine def in defines)
\r
208 def.WriteRnc (this);
\r
211 private void WriteQName (string name, string ns)
\r
213 WriteQName (name, ns, nsmgr);
\r
216 private void WriteQName (string name, string ns, NSResolver nss)
\r
218 string prefix = String.Empty;
\r
219 if (ns != null && ns != String.Empty) {
\r
222 // XmlNamespaceManager sucks.
\r
223 ns = nss.NameTable.Add (ns);
\r
225 prefix = nss.LookupPrefix (ns);
\r
227 if (prefix == null)
\r
228 throw new RelaxngException (String.Format ("Namespace '{0}' is not mapped to a prefix in argument XmlNamespaceManager.", ns));
\r
229 if (prefix != String.Empty) {
\r
233 if (IsKeyword (name))
\r
238 private void WriteLiteral (string value)
\r
241 for (int i = 0; i < value.Length; i++) {
\r
242 switch (value [i]) {
\r
244 w.Write ("\\x{22}");
\r
247 w.Write ("\\x{13}");
\r
250 w.Write ("\\x{10}");
\r
252 case '\t': // It is not required, but would be better.
\r
253 w.Write ("\\x{9}");
\r
256 w.Write (value [i]);
\r
265 public void WriteNamespaces (string defaultNamespace)
\r
267 WriteNamespaces (defaultNamespace, nsmgr, false);
\r
268 WriteNamespaces (null, datansmgr, true);
\r
271 public void WriteNamespaces (string defaultNamespace, NSResolver nsmgr, bool isData)
\r
273 if (defaultNamespace == null)
\r
274 defaultNamespace = String.Empty;
\r
276 if (defaultNamespace.Length > 0)
\r
277 w.WriteLine ("default namespace = {0}",
\r
280 if (nsmgr != null) {
\r
282 foreach (string s in nsmgr.GetNamespacesInScope (
\r
283 XmlNamespaceScope.All).Keys) {
\r
285 foreach (string s in nsmgr) {
\r
292 if (defaultNamespace.Length > 0)
\r
293 w.WriteLine ("default namespace = '{0}'",
\r
294 nsmgr.LookupNamespace (s).Replace ('\'', '\"'));
\r
297 w.WriteLine ("{2} {0} = '{1}'",
\r
299 nsmgr.LookupNamespace (s).Replace ('\'', '\"'),
\r
300 isData ? "datatypes" : "namespace");
\r
309 // Note that it might not be used directly when a grammar
\r
310 // contains more than one "start" (compact syntax does not
\r
311 // support "combine" attribute).
\r
312 public void WriteStart (RelaxngStart start)
\r
315 if (start.Combine == null)
\r
318 w.Write (start.Combine.Trim () == "interleave" ?
\r
320 start.Pattern.WriteRnc (this);
\r
324 // Note that it might not be used directly when a grammar
\r
325 // contains more than one "define" for an identical name
\r
326 // (compact syntax does not support "combine" attribute).
\r
327 public void WriteDefine (RelaxngDefine define)
\r
329 if (IsKeyword (define.Name))
\r
331 w.Write (define.Name);
\r
332 if (define.Combine == null)
\r
335 w.Write (define.Combine.Trim () == "interleave" ?
\r
337 if (define.Patterns.Count == 0)
\r
340 define.Patterns [0].WriteRnc (this);
\r
341 for (int i = 1; i < define.Patterns.Count; i++) {
\r
343 define.Patterns [i].WriteRnc (this);
\r
350 public void WriteInclude (RelaxngInclude include)
\r
352 w.Write ("include ");
\r
353 w.Write (include.Href);
\r
355 // FIXME: optInherit?
\r
357 if (include.Starts.Count > 0 ||
\r
358 include.Defines.Count > 0 ||
\r
359 include.Divs.Count > 0) {
\r
361 WriteGrammarIncludeContents (include.Starts,
\r
362 include.Defines, include.Divs, null);
\r
368 public void WriteDiv (RelaxngDiv div)
\r
370 w.Write ("div { ");
\r
371 WriteGrammarIncludeContents (div.Starts,
\r
372 div.Defines, div.Divs, div.Includes);
\r
376 public void WriteNotAllowed (RelaxngNotAllowed na)
\r
378 w.Write ("notAllowed ");
\r
381 public void WriteEmpty (RelaxngEmpty empty)
\r
383 w.Write ("empty ");
\r
386 public void WriteText (RelaxngText text)
\r
391 public void WriteData (RelaxngData data)
\r
393 WriteQName (data.Type, data.DatatypeLibrary, datansmgr);
\r
394 if (data.ParamList.Count > 0) {
\r
396 foreach (RelaxngParam p in data.ParamList)
\r
400 if (data.Except != null)
\r
401 data.Except.WriteRnc (this);
\r
404 public void WriteValue (RelaxngValue v)
\r
406 WriteQName (v.Type, v.DatatypeLibrary, datansmgr);
\r
408 WriteLiteral (v.Value);
\r
411 public void WriteList (RelaxngList p)
\r
413 w.Write ("list {");
\r
414 WritePatterns (p.Patterns, false);
\r
418 public void WriteMixed (RelaxngMixed p)
\r
420 w.Write ("mixed {");
\r
421 WritePatterns (p.Patterns, false);
\r
425 public void WriteElement (RelaxngElement element)
\r
427 w.Write ("element ");
\r
428 element.NameClass.WriteRnc (this);
\r
430 WritePatterns (element.Patterns, false);
\r
434 public void WriteAttribute (RelaxngAttribute attribute)
\r
436 w.Write ("attribute ");
\r
437 attribute.NameClass.WriteRnc (this);
\r
439 if (attribute.Pattern == null)
\r
442 attribute.Pattern.WriteRnc (this);
\r
446 public void WriteRef (RelaxngRef r)
\r
448 if (IsKeyword (r.Name))
\r
453 public void WriteParentRef (RelaxngParentRef r)
\r
455 w.Write ("parent ");
\r
456 if (IsKeyword (r.Name))
\r
462 public void WriteExternalRef (RelaxngExternalRef r)
\r
464 w.Write ("external ");
\r
466 // FIXME: optInherit?
\r
470 public void WriteOneOrMore (RelaxngOneOrMore p)
\r
472 WritePatterns (p.Patterns, true);
\r
476 public void WriteZeroOrMore (RelaxngZeroOrMore p)
\r
478 WritePatterns (p.Patterns, true);
\r
482 public void WriteOptional (RelaxngOptional p)
\r
484 WritePatterns (p.Patterns, true);
\r
488 public void WriteChoice (RelaxngChoice p)
\r
490 WritePatterns (p.Patterns, '|', false);
\r
493 public void WriteGroup (RelaxngGroup p)
\r
495 WritePatterns (p.Patterns, ',', false);
\r
498 public void WriteInterleave (RelaxngInterleave p)
\r
500 WritePatterns (p.Patterns, '&', false);
\r
503 public void WriteParam (RelaxngParam p)
\r
505 if (IsKeyword (p.Name))
\r
509 WriteLiteral (p.Value);
\r
512 public void WriteDataExcept (RelaxngExcept e)
\r
515 WritePatterns (e.Patterns, true);
\r
518 public void WriteGrammar (RelaxngGrammar g)
\r
520 w.WriteLine ("grammar {");
\r
521 WriteGrammarIncludeContents (g.Starts,
\r
522 g.Defines, g.Divs, g.Includes);
\r
526 public void WriteAnyName (RelaxngAnyName n)
\r
529 if (n.Except != null)
\r
530 n.Except.WriteRnc (this);
\r
533 public void WriteNsName (RelaxngNsName n)
\r
535 WriteQName ("*", n.Namespace);
\r
536 if (n.Except != null)
\r
537 n.Except.WriteRnc (this);
\r
540 public void WriteName (RelaxngName n)
\r
542 WriteQName (n.LocalName, n.Namespace);
\r
545 public void WriteNameChoice (RelaxngNameChoice c)
\r
547 WriteNames (c.Children, false);
\r
550 public void WriteNameExcept (RelaxngExceptNameClass e)
\r
553 WriteNames (e.Names, true);
\r