2 // Commons.Xml.Relaxng.RelaxngReader.cs
5 // Atsushi Enomoto <ginga@kit.hi-ho.ne.jp>
7 // 2003 Atsushi Enomoto "No rights reserved."
9 // Copyright (c) 2004 Novell Inc.
10 // All rights reserved
14 // Permission is hereby granted, free of charge, to any person obtaining
15 // a copy of this software and associated documentation files (the
16 // "Software"), to deal in the Software without restriction, including
17 // without limitation the rights to use, copy, modify, merge, publish,
18 // distribute, sublicense, and/or sell copies of the Software, and to
19 // permit persons to whom the Software is furnished to do so, subject to
20 // the following conditions:
22 // The above copyright notice and this permission notice shall be
23 // included in all copies or substantial portions of the Software.
25 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
29 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
30 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
31 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
35 using System.Collections;
38 namespace Commons.Xml.Relaxng
40 public class RelaxngReader : XmlDefaultReader
43 static RelaxngPattern grammarForRelaxng;
44 static XmlReader relaxngXmlReader;
45 static RelaxngReader ()
47 relaxngXmlReader = new XmlTextReader (typeof (RelaxngReader).Assembly.GetManifestResourceStream ("relaxng.rng"));
49 RelaxngPattern.Read (relaxngXmlReader);
52 [Obsolete] // incorrectly introduced
53 public static string RelaxngNS = "http://relaxng.org/ns/structure/1.0";
54 public static RelaxngPattern GrammarForRelaxng {
55 get { return grammarForRelaxng; }
60 Stack nsStack = new Stack ();
61 Stack datatypeLibraryStack = new Stack ();
62 XmlResolver resolver = new XmlUrlResolver ();
63 // ArrayList annotationNamespaces = new ArrayList ();
66 public RelaxngReader (XmlReader reader)
71 public RelaxngReader (XmlReader reader, string ns)
72 // : base (grammarForRelaxng == null ? reader : new RelaxngValidatingReader (reader, grammarForRelaxng))
75 if (Reader.ReadState == ReadState.Initial)
78 string nsval = GetSpaceStrippedAttribute ("ns", String.Empty);
81 nsStack.Push (nsval == null ? String.Empty : nsval);
82 string dtlib = GetSpaceStrippedAttribute ("datatypeLibrary", String.Empty);
83 datatypeLibraryStack.Push (dtlib != null ?
84 dtlib : String.Empty);
87 public XmlResolver XmlResolver {
88 set { resolver = value; }
91 internal XmlResolver Resolver {
92 get { return resolver; }
95 private void FillLocation (RelaxngElementBase el)
98 IXmlLineInfo li = this as IXmlLineInfo;
99 el.LineNumber = li != null ? li.LineNumber : 0;
100 el.LinePosition = li != null ? li.LinePosition : 0;
104 public void AddAnnotationNamespace (string ns)
106 if (!annotationNamespaces.Contains (ns))
107 annotationNamespaces.Add (ns);
112 public override bool Read ()
114 bool skipRead = false;
117 if (IsEmptyElement) { // this should be done here
119 datatypeLibraryStack.Pop ();
127 case XmlNodeType.ProcessingInstruction:
128 case XmlNodeType.Comment:
129 case XmlNodeType.EntityReference:
131 case XmlNodeType.Whitespace:
132 // Skip whitespaces except for data and param.
133 case XmlNodeType.SignificantWhitespace:
134 if (LocalName != "value" && LocalName != "param") {
141 if (NamespaceURI != RelaxngGrammar.NamespaceURI) {
149 } while (!Reader.EOF && loop);
152 case XmlNodeType.Element:
153 if (MoveToAttribute ("ns")) {
154 nsStack.Push (Value.Trim ());
158 nsStack.Push (ContextNamespace);
160 if (MoveToAttribute ("datatypeLibrary")) {
161 string uriString = Value.Trim ();
162 if (uriString.Length == 0)
163 datatypeLibraryStack.Push (String.Empty);
166 Uri uri = new Uri (uriString);
167 // MS.NET Uri is too lamespec
168 datatypeLibraryStack.Push (uri.ToString ());
169 } catch (UriFormatException ex) {
170 throw new RelaxngException (ex.Message, ex);
176 datatypeLibraryStack.Push (DatatypeLibrary);
179 case XmlNodeType.EndElement:
181 datatypeLibraryStack.Pop ();
190 public string ContextNamespace {
192 if (nsStack.Count == 0)
193 // It happens only on initialization.
195 return nsStack.Peek () as string;
199 public string DatatypeLibrary {
201 if (datatypeLibraryStack.Count == 0)
202 // It happens only on initialization.
204 return datatypeLibraryStack.Peek () as string;
209 private void expect (string name)
211 if (NamespaceURI != RelaxngGrammar.NamespaceURI)
212 throw new RelaxngException (String.Format ("Invalid document: expected namespace {0} but found {1}", RelaxngGrammar.NamespaceURI, NamespaceURI));
213 else if (LocalName != name)
214 throw new RelaxngException (String.Format ("Invalid document: expected local name {0} but found {1}", name, LocalName));
217 private void expectEnd (string name)
219 if (NodeType != XmlNodeType.EndElement)
220 throw new RelaxngException (String.Format ("Expected EndElement but found {0}.", NodeType));
226 // Other than name class and pattern.
227 private RelaxngStart ReadStart ()
229 RelaxngStart s = new RelaxngStart ();
233 if (MoveToFirstAttribute ()) {
235 if (NamespaceURI != String.Empty)
238 case "datatypeLibrary":
242 throw new RelaxngException ("Invalid attribute.");
244 } while (MoveToNextAttribute ());
248 if (MoveToAttribute ("combine")) {
249 s.Combine = Value.Trim ();
250 if (s.Combine != "choice" && s.Combine != "interleave")
251 throw new RelaxngException ("Invalid combine attribute: " + s.Combine);
256 s.Pattern = ReadPattern ();
261 private string GetNameAttribute ()
263 string name = GetSpaceStrippedAttribute ("name", String.Empty);
265 throw new RelaxngException ("Required attribute name is not found.");
266 return XmlConvert.VerifyNCName (name);
269 private string GetSpaceStrippedAttribute (string name, string ns)
271 string v = GetAttribute (name, ns);
272 return v != null ? v.Trim () : null;
275 private RelaxngDefine ReadDefine ()
277 RelaxngDefine def = new RelaxngDefine ();
280 def.Name = GetNameAttribute ();
281 def.Combine = GetSpaceStrippedAttribute ("combine", String.Empty);
284 while (NodeType == XmlNodeType.Element)
285 def.Patterns.Add (ReadPattern ());
286 expectEnd ("define");
290 private RelaxngParam ReadParam ()
292 RelaxngParam p = new RelaxngParam ();
295 p.Name = GetNameAttribute ();
296 p.Value = ReadString ().Trim ();
301 // NameClass reader (only if it is element-style.)
302 private RelaxngNameClass ReadNameClass ()
306 return ReadNameClassName ();
308 return ReadNameClassAnyName ();
310 return ReadNameClassNsName ();
312 return ReadNameClassChoice ();
314 throw new RelaxngException ("Invalid name class: " + LocalName);
317 private RelaxngName ReadNameClassName ()
319 string name = ReadString ().Trim ();
320 RelaxngName rName = resolvedName (name);
325 private RelaxngAnyName ReadNameClassAnyName ()
327 RelaxngAnyName an = new RelaxngAnyName ();
329 if (!IsEmptyElement) {
331 if (NodeType == XmlNodeType.EndElement) {
336 an.Except = new RelaxngExceptNameClass ();
337 FillLocation (an.Except);
338 while (NodeType == XmlNodeType.Element)
339 an.Except.Names.Add (
341 expectEnd ("except");
343 expectEnd ("anyName");
349 private RelaxngNsName ReadNameClassNsName ()
351 RelaxngNsName nn = new RelaxngNsName ();
353 nn.Namespace = this.ContextNamespace;
354 if (!IsEmptyElement) {
356 if (NodeType == XmlNodeType.EndElement) {
361 nn.Except = ReadNameClassExcept ();//new RelaxngExceptNameClass ();
362 FillLocation (nn.Except);
364 expectEnd ("nsName");
370 private RelaxngNameChoice ReadNameClassChoice ()
372 RelaxngNameChoice nc = new RelaxngNameChoice ();
375 throw new RelaxngException ("Name choice must have at least one name class.");
378 while (NodeType != XmlNodeType.EndElement) {
379 nc.Children.Add (ReadNameClass ());
381 if (nc.Children.Count == 0)
382 throw new RelaxngException ("Name choice must have at least one name class.");
384 expectEnd ("choice");
388 private RelaxngExceptNameClass ReadNameClassExcept ()
390 RelaxngExceptNameClass x = new RelaxngExceptNameClass ();
393 throw new RelaxngException ("Name choice must have at least one name class.");
396 while (NodeType != XmlNodeType.EndElement)
397 x.Names.Add (ReadNameClass ());
398 if (x.Names.Count == 0)
399 throw new RelaxngException ("Name choice must have at least one name class.");
401 expectEnd ("except");
407 public RelaxngPattern ReadPattern ()
409 while (NodeType != XmlNodeType.Element)
411 throw new RelaxngException ("RELAX NG pattern did not appear.");
415 return ReadElementPattern ();
417 return ReadAttributePattern ();
419 return ReadGroupPattern ();
421 return ReadInterleavePattern ();
423 return ReadChoicePattern ();
425 return ReadOptionalPattern ();
427 return ReadZeroOrMorePattern ();
429 return ReadOneOrMorePattern ();
431 return ReadListPattern ();
433 return ReadMixedPattern ();
435 return ReadRefPattern ();
437 return ReadParentRefPattern ();
439 return ReadEmptyPattern ();
441 return ReadTextPattern ();
443 return ReadDataPattern ();
445 return ReadValuePattern ();
447 return ReadNotAllowedPattern ();
449 return ReadExternalRefPattern ();
451 return ReadGrammarPattern ();
453 throw new RelaxngException ("Non-supported pattern specification: " + LocalName);
456 private void ReadPatterns (RelaxngSingleContentPattern el)
459 el.Patterns.Add (ReadPattern ());
460 } while (NodeType == XmlNodeType.Element);
463 private void ReadPatterns (RelaxngBinaryContentPattern el)
466 el.Patterns.Add (ReadPattern ());
467 } while (NodeType == XmlNodeType.Element);
470 private RelaxngExcept ReadPatternExcept ()
472 RelaxngExcept x = new RelaxngExcept ();
475 throw new RelaxngException ("'except' must have at least one pattern.");
477 while (NodeType != XmlNodeType.EndElement)
478 x.Patterns.Add (ReadPattern ());
479 if (x.Patterns.Count == 0)
480 throw new RelaxngException ("'except' must have at least one pattern.");
482 expectEnd ("except");
486 private RelaxngInclude ReadInclude ()
488 RelaxngInclude i = new RelaxngInclude ();
491 i.NSContext = ContextNamespace;
492 string href = GetSpaceStrippedAttribute ("href", String.Empty);
494 throw new RelaxngException ("Required attribute href was not found.");
495 XmlResolver res = resolver != null ? resolver : new XmlUrlResolver ();
496 i.Href = res.ResolveUri (BaseURI != null ? new Uri (BaseURI) : null, href).AbsoluteUri;
497 if (!IsEmptyElement) {
499 this.readGrammarIncludeContent (i.Starts, i.Defines, i.Divs, null);
500 expectEnd ("include");
507 private void readGrammarIncludeContent (IList starts, IList defines, IList divs, IList includes)
509 while (NodeType == XmlNodeType.Element) {
512 starts.Add (ReadStart ());
515 defines.Add (ReadDefine ());
518 divs.Add (ReadDiv (includes != null));
521 if (includes != null)
522 includes.Add (ReadInclude ());
524 throw new RelaxngException ("Unexpected content: " + Name);
527 throw new RelaxngException ("Unexpected content: " + Name);
532 private RelaxngDiv ReadDiv (bool allowIncludes)
535 RelaxngDiv div = new RelaxngDiv ();
537 if (!IsEmptyElement) {
539 readGrammarIncludeContent (div.Starts, div.Defines, div.Divs, div.Includes);
547 private RelaxngName resolvedName (string nameSpec)
549 int colonAt = nameSpec.IndexOf (':');
550 string prefix = (colonAt < 0) ? "" : nameSpec.Substring (0, colonAt);
551 string local = (colonAt < 0) ? nameSpec : nameSpec.Substring (colonAt + 1, nameSpec.Length - colonAt - 1);
552 string uri = ContextNamespace;
555 uri = LookupNamespace (prefix);
557 throw new RelaxngException ("Undeclared prefix in name component: " + nameSpec);
559 RelaxngName n = new RelaxngName (local, uri);
564 private RelaxngElement ReadElementPattern ()
566 RelaxngElement el = new RelaxngElement ();
569 if (MoveToFirstAttribute ()) {
571 if (NamespaceURI != String.Empty)
574 case "datatypeLibrary":
579 throw new RelaxngException ("Invalid attribute.");
581 } while (MoveToNextAttribute ());
585 // try to get name from attribute.
586 if (MoveToAttribute ("name"))
587 el.NameClass = resolvedName (XmlConvert.VerifyName (Value.Trim ()));
591 // read nameClass from content.
592 if (el.NameClass == null)
593 el.NameClass = ReadNameClass ();
596 this.ReadPatterns (el);
598 expectEnd ("element");
600 if (el.NameClass == null)
601 throw new RelaxngException ("Name class was not specified.");
605 private RelaxngAttribute ReadAttributePattern ()
607 RelaxngAttribute attr = new RelaxngAttribute ();
610 if (MoveToFirstAttribute ()) {
612 if (NamespaceURI != String.Empty)
615 case "datatypeLibrary":
620 throw new RelaxngException ("Invalid attribute.");
622 } while (MoveToNextAttribute ());
626 string ns = GetSpaceStrippedAttribute ("ns", String.Empty);
628 // try to get name from attribute.
629 if (MoveToAttribute ("name", String.Empty)) {
630 // attr.NameClass = resolvedName (XmlConvert.VerifyName (Value.Trim ()), false);
631 RelaxngName nc = new RelaxngName ();
632 string name = XmlConvert.VerifyName (Value.Trim ());
633 if (name.IndexOf (':') > 0)
634 nc = resolvedName (name);
637 nc.Namespace = ns == null ? String.Empty : ns;
643 if (!IsEmptyElement) {
645 // read nameClass from content.
646 if (attr.NameClass == null)
647 attr.NameClass = ReadNameClass ();
649 if (NodeType == XmlNodeType.Element)
650 attr.Pattern = ReadPattern ();
652 expectEnd ("attribute");
656 if (attr.NameClass == null)
657 throw new RelaxngException ("Name class was not specified.");
661 private RelaxngGrammar ReadGrammarPattern ()
663 RelaxngGrammar grammar = new RelaxngGrammar ();
664 FillLocation (grammar);
665 grammar.DefaultNamespace = Reader.GetAttribute ("ns");
667 this.readGrammarIncludeContent (grammar.Starts, grammar.Defines, grammar.Divs, grammar.Includes);
668 expectEnd ("grammar");
673 private RelaxngRef ReadRefPattern ()
675 RelaxngRef r = new RelaxngRef ();
678 r.Name = GetNameAttribute ();
679 if (!IsEmptyElement) {
688 private RelaxngExternalRef ReadExternalRefPattern ()
690 RelaxngExternalRef r = new RelaxngExternalRef ();
692 expect ("externalRef");
693 string href = GetSpaceStrippedAttribute ("href", String.Empty);
695 throw new RelaxngException ("Required attribute href was not found.");
696 XmlResolver res = resolver != null ? resolver : new XmlUrlResolver ();
697 r.Href = res.ResolveUri (BaseURI != null ? new Uri (BaseURI) : null, href).AbsoluteUri;
698 r.NSContext = ContextNamespace;
699 if (!IsEmptyElement) {
701 expectEnd ("externalRef");
708 private RelaxngParentRef ReadParentRefPattern ()
710 RelaxngParentRef r = new RelaxngParentRef ();
712 expect ("parentRef");
713 r.Name = GetNameAttribute ();
714 if (!IsEmptyElement) {
716 expectEnd ("parentRef");
723 private RelaxngEmpty ReadEmptyPattern ()
727 if (MoveToFirstAttribute ()) {
729 if (NamespaceURI == String.Empty && LocalName != "datatypeLibrary")
730 throw new RelaxngException ("Invalid attribute.");
731 } while (MoveToNextAttribute ());
735 if (!IsEmptyElement) {
742 RelaxngEmpty empty = new RelaxngEmpty ();
743 FillLocation (empty);
747 private RelaxngText ReadTextPattern ()
751 if (MoveToFirstAttribute ()) {
753 if (NamespaceURI == String.Empty && LocalName != "datatypeLibrary")
754 throw new RelaxngException ("Invalid attribute.");
755 } while (MoveToNextAttribute ());
759 if (!IsEmptyElement) {
766 RelaxngText t = new RelaxngText ();
771 private RelaxngData ReadDataPattern ()
773 RelaxngData data = new RelaxngData ();
777 data.Type = GetSpaceStrippedAttribute ("type", String.Empty);
778 if (data.Type == null)
779 throw new RelaxngException ("Attribute type is required.");
780 data.DatatypeLibrary = DatatypeLibrary;
782 if (MoveToFirstAttribute ()) {
784 if (NamespaceURI != String.Empty)
787 case "datatypeLibrary":
791 throw new RelaxngException ("Invalid attribute.");
793 } while (MoveToNextAttribute ());
797 if (!IsEmptyElement) {
799 while (Name == "param") {
800 data.ParamList.Add (ReadParam ());
802 if (LocalName == "except")
803 data.Except = ReadPatternExcept ();
811 private RelaxngValue ReadValuePattern ()
813 RelaxngValue v = new RelaxngValue ();
817 if (MoveToFirstAttribute ()) {
819 if (NamespaceURI != String.Empty)
822 case "datatypeLibrary":
827 throw new RelaxngException ("Invalid attribute.");
829 } while (MoveToNextAttribute ());
833 if (MoveToAttribute ("type")) {
834 v.Type = Value.Trim ();
835 v.DatatypeLibrary = DatatypeLibrary;
838 v.DatatypeLibrary = "";
840 // v.Namespace = GetSpaceStrippedAttribute ("ns", String.Empty);
842 if (IsEmptyElement) {
843 v.Value = String.Empty;
846 v.Value = ReadString ();
853 private RelaxngList ReadListPattern ()
855 RelaxngList list = new RelaxngList ();
864 private RelaxngOneOrMore ReadOneOrMorePattern ()
866 RelaxngOneOrMore o = new RelaxngOneOrMore ();
868 expect ("oneOrMore");
871 expectEnd ("oneOrMore");
875 private RelaxngZeroOrMore ReadZeroOrMorePattern ()
877 RelaxngZeroOrMore o = new RelaxngZeroOrMore ();
879 expect ("zeroOrMore");
882 expectEnd ("zeroOrMore");
886 private RelaxngOptional ReadOptionalPattern ()
888 RelaxngOptional o = new RelaxngOptional ();
893 expectEnd ("optional");
897 private RelaxngMixed ReadMixedPattern ()
899 RelaxngMixed o = new RelaxngMixed ();
908 private RelaxngGroup ReadGroupPattern ()
910 RelaxngGroup g = new RelaxngGroup ();
919 private RelaxngInterleave ReadInterleavePattern ()
921 RelaxngInterleave i = new RelaxngInterleave ();
923 expect ("interleave");
926 expectEnd ("interleave");
930 private RelaxngChoice ReadChoicePattern ()
932 RelaxngChoice c = new RelaxngChoice ();
937 expectEnd ("choice");
941 private RelaxngNotAllowed ReadNotAllowedPattern ()
943 expect ("notAllowed");
944 if (!IsEmptyElement) {
946 expectEnd ("notAllowed");
950 RelaxngNotAllowed na = new RelaxngNotAllowed ();