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 ();
63 // ArrayList annotationNamespaces = new ArrayList ();
66 public RelaxngReader (XmlReader reader)
71 public RelaxngReader (XmlReader reader, string ns)
72 : this (reader, ns, new XmlUrlResolver ())
76 public RelaxngReader (XmlReader reader, string ns, XmlResolver resolver)
77 // : base (grammarForRelaxng == null ? reader : new RelaxngValidatingReader (reader, grammarForRelaxng))
80 this.resolver = resolver;
81 if (Reader.ReadState == ReadState.Initial)
84 string nsval = GetSpaceStrippedAttribute ("ns", String.Empty);
87 nsStack.Push (nsval == null ? String.Empty : nsval);
88 string dtlib = GetSpaceStrippedAttribute ("datatypeLibrary", String.Empty);
89 datatypeLibraryStack.Push (dtlib != null ?
90 dtlib : String.Empty);
93 public XmlResolver XmlResolver {
94 set { resolver = value; }
97 internal XmlResolver Resolver {
98 get { return resolver; }
101 private void FillLocation (RelaxngElementBase el)
103 el.BaseUri = BaseURI;
104 IXmlLineInfo li = this as IXmlLineInfo;
105 el.LineNumber = li != null ? li.LineNumber : 0;
106 el.LinePosition = li != null ? li.LinePosition : 0;
110 public void AddAnnotationNamespace (string ns)
112 if (!annotationNamespaces.Contains (ns))
113 annotationNamespaces.Add (ns);
118 public override bool Read ()
120 bool skipRead = false;
123 if (IsEmptyElement) { // this should be done here
125 datatypeLibraryStack.Pop ();
133 case XmlNodeType.ProcessingInstruction:
134 case XmlNodeType.Comment:
135 case XmlNodeType.EntityReference:
137 case XmlNodeType.Whitespace:
138 // Skip whitespaces except for data and param.
139 case XmlNodeType.SignificantWhitespace:
140 if (LocalName != "value" && LocalName != "param") {
147 if (NamespaceURI != RelaxngGrammar.NamespaceURI) {
155 } while (!Reader.EOF && loop);
158 case XmlNodeType.Element:
159 if (MoveToAttribute ("ns")) {
160 nsStack.Push (Value.Trim ());
164 nsStack.Push (ContextNamespace);
166 if (MoveToAttribute ("datatypeLibrary")) {
167 string uriString = Value.Trim ();
168 if (uriString.Length == 0)
169 datatypeLibraryStack.Push (String.Empty);
172 Uri uri = new Uri (uriString);
173 // MS.NET Uri is too lamespec
174 datatypeLibraryStack.Push (uri.ToString ());
175 } catch (UriFormatException ex) {
176 throw new RelaxngException (ex.Message, ex);
182 datatypeLibraryStack.Push (DatatypeLibrary);
185 case XmlNodeType.EndElement:
187 datatypeLibraryStack.Pop ();
196 public string ContextNamespace {
198 if (nsStack.Count == 0)
199 // It happens only on initialization.
201 return nsStack.Peek () as string;
205 public string DatatypeLibrary {
207 if (datatypeLibraryStack.Count == 0)
208 // It happens only on initialization.
210 return datatypeLibraryStack.Peek () as string;
215 private void expect (string name)
217 if (NamespaceURI != RelaxngGrammar.NamespaceURI)
218 throw new RelaxngException (String.Format ("Invalid document: expected namespace {0} but found {1}", RelaxngGrammar.NamespaceURI, NamespaceURI));
219 else if (LocalName != name)
220 throw new RelaxngException (String.Format ("Invalid document: expected local name {0} but found {1}", name, LocalName));
223 private void expectEnd (string name)
225 if (NodeType != XmlNodeType.EndElement)
226 throw new RelaxngException (String.Format ("Expected EndElement but found {0}.", NodeType));
232 // Other than name class and pattern.
233 private RelaxngStart ReadStart ()
235 RelaxngStart s = new RelaxngStart ();
239 if (MoveToFirstAttribute ()) {
241 if (NamespaceURI != String.Empty)
244 case "datatypeLibrary":
248 throw new RelaxngException ("Invalid attribute.");
250 } while (MoveToNextAttribute ());
254 if (MoveToAttribute ("combine")) {
255 s.Combine = Value.Trim ();
256 if (s.Combine != "choice" && s.Combine != "interleave")
257 throw new RelaxngException ("Invalid combine attribute: " + s.Combine);
262 s.Pattern = ReadPattern ();
267 private string GetNameAttribute ()
269 string name = GetSpaceStrippedAttribute ("name", String.Empty);
271 throw new RelaxngException ("Required attribute name is not found.");
272 return XmlConvert.VerifyNCName (name);
275 private string GetSpaceStrippedAttribute (string name, string ns)
277 string v = GetAttribute (name, ns);
278 return v != null ? v.Trim () : null;
281 private RelaxngDefine ReadDefine ()
283 RelaxngDefine def = new RelaxngDefine ();
286 def.Name = GetNameAttribute ();
287 def.Combine = GetSpaceStrippedAttribute ("combine", String.Empty);
290 while (NodeType == XmlNodeType.Element)
291 def.Patterns.Add (ReadPattern ());
292 expectEnd ("define");
296 private RelaxngParam ReadParam ()
298 RelaxngParam p = new RelaxngParam ();
301 p.Name = GetNameAttribute ();
302 p.Value = ReadString ().Trim ();
307 // NameClass reader (only if it is element-style.)
308 private RelaxngNameClass ReadNameClass ()
312 return ReadNameClassName ();
314 return ReadNameClassAnyName ();
316 return ReadNameClassNsName ();
318 return ReadNameClassChoice ();
320 throw new RelaxngException ("Invalid name class: " + LocalName);
323 private RelaxngName ReadNameClassName ()
325 string name = ReadString ().Trim ();
326 RelaxngName rName = resolvedName (name);
331 private RelaxngAnyName ReadNameClassAnyName ()
333 RelaxngAnyName an = new RelaxngAnyName ();
335 if (!IsEmptyElement) {
337 if (NodeType == XmlNodeType.EndElement) {
342 an.Except = new RelaxngExceptNameClass ();
343 FillLocation (an.Except);
344 while (NodeType == XmlNodeType.Element)
345 an.Except.Names.Add (
347 expectEnd ("except");
349 expectEnd ("anyName");
355 private RelaxngNsName ReadNameClassNsName ()
357 RelaxngNsName nn = new RelaxngNsName ();
359 nn.Namespace = this.ContextNamespace;
360 if (!IsEmptyElement) {
362 if (NodeType == XmlNodeType.EndElement) {
367 nn.Except = ReadNameClassExcept ();//new RelaxngExceptNameClass ();
368 FillLocation (nn.Except);
370 expectEnd ("nsName");
376 private RelaxngNameChoice ReadNameClassChoice ()
378 RelaxngNameChoice nc = new RelaxngNameChoice ();
381 throw new RelaxngException ("Name choice must have at least one name class.");
384 while (NodeType != XmlNodeType.EndElement) {
385 nc.Children.Add (ReadNameClass ());
387 if (nc.Children.Count == 0)
388 throw new RelaxngException ("Name choice must have at least one name class.");
390 expectEnd ("choice");
394 private RelaxngExceptNameClass ReadNameClassExcept ()
396 RelaxngExceptNameClass x = new RelaxngExceptNameClass ();
399 throw new RelaxngException ("Name choice must have at least one name class.");
402 while (NodeType != XmlNodeType.EndElement)
403 x.Names.Add (ReadNameClass ());
404 if (x.Names.Count == 0)
405 throw new RelaxngException ("Name choice must have at least one name class.");
407 expectEnd ("except");
413 public RelaxngPattern ReadPattern ()
415 while (NodeType != XmlNodeType.Element)
417 throw new RelaxngException ("RELAX NG pattern did not appear.");
421 return ReadElementPattern ();
423 return ReadAttributePattern ();
425 return ReadGroupPattern ();
427 return ReadInterleavePattern ();
429 return ReadChoicePattern ();
431 return ReadOptionalPattern ();
433 return ReadZeroOrMorePattern ();
435 return ReadOneOrMorePattern ();
437 return ReadListPattern ();
439 return ReadMixedPattern ();
441 return ReadRefPattern ();
443 return ReadParentRefPattern ();
445 return ReadEmptyPattern ();
447 return ReadTextPattern ();
449 return ReadDataPattern ();
451 return ReadValuePattern ();
453 return ReadNotAllowedPattern ();
455 return ReadExternalRefPattern ();
457 return ReadGrammarPattern ();
459 throw new RelaxngException ("Non-supported pattern specification: " + LocalName);
462 private void ReadPatterns (RelaxngSingleContentPattern el)
465 el.Patterns.Add (ReadPattern ());
466 } while (NodeType == XmlNodeType.Element);
469 private void ReadPatterns (RelaxngBinaryContentPattern el)
472 el.Patterns.Add (ReadPattern ());
473 } while (NodeType == XmlNodeType.Element);
476 private RelaxngExcept ReadPatternExcept ()
478 RelaxngExcept x = new RelaxngExcept ();
481 throw new RelaxngException ("'except' must have at least one pattern.");
483 while (NodeType != XmlNodeType.EndElement)
484 x.Patterns.Add (ReadPattern ());
485 if (x.Patterns.Count == 0)
486 throw new RelaxngException ("'except' must have at least one pattern.");
488 expectEnd ("except");
492 private RelaxngInclude ReadInclude ()
494 RelaxngInclude i = new RelaxngInclude ();
497 i.NSContext = ContextNamespace;
498 string href = GetSpaceStrippedAttribute ("href", String.Empty);
500 throw new RelaxngException ("Required attribute href was not found.");
501 XmlResolver res = resolver != null ? resolver : new XmlUrlResolver ();
502 i.Href = res.ResolveUri (BaseURI != null ? new Uri (BaseURI) : null, href).AbsoluteUri;
503 if (!IsEmptyElement) {
505 this.readGrammarIncludeContent (i.Starts, i.Defines, i.Divs, null);
506 expectEnd ("include");
513 private void readGrammarIncludeContent (IList starts, IList defines, IList divs, IList includes)
515 while (NodeType == XmlNodeType.Element) {
518 starts.Add (ReadStart ());
521 defines.Add (ReadDefine ());
524 divs.Add (ReadDiv (includes != null));
527 if (includes != null)
528 includes.Add (ReadInclude ());
530 throw new RelaxngException ("Unexpected content: " + Name);
533 throw new RelaxngException ("Unexpected content: " + Name);
538 private RelaxngDiv ReadDiv (bool allowIncludes)
541 RelaxngDiv div = new RelaxngDiv ();
543 if (!IsEmptyElement) {
545 readGrammarIncludeContent (div.Starts, div.Defines, div.Divs, div.Includes);
553 private RelaxngName resolvedName (string nameSpec)
555 int colonAt = nameSpec.IndexOf (':');
556 string prefix = (colonAt < 0) ? "" : nameSpec.Substring (0, colonAt);
557 string local = (colonAt < 0) ? nameSpec : nameSpec.Substring (colonAt + 1, nameSpec.Length - colonAt - 1);
558 string uri = ContextNamespace;
561 uri = LookupNamespace (prefix);
563 throw new RelaxngException ("Undeclared prefix in name component: " + nameSpec);
565 RelaxngName n = new RelaxngName (local, uri);
570 private RelaxngElement ReadElementPattern ()
572 RelaxngElement el = new RelaxngElement ();
575 if (MoveToFirstAttribute ()) {
577 if (NamespaceURI != String.Empty)
580 case "datatypeLibrary":
585 throw new RelaxngException ("Invalid attribute.");
587 } while (MoveToNextAttribute ());
591 // try to get name from attribute.
592 if (MoveToAttribute ("name"))
593 el.NameClass = resolvedName (XmlConvert.VerifyName (Value.Trim ()));
597 // read nameClass from content.
598 if (el.NameClass == null)
599 el.NameClass = ReadNameClass ();
602 this.ReadPatterns (el);
604 expectEnd ("element");
606 if (el.NameClass == null)
607 throw new RelaxngException ("Name class was not specified.");
611 private RelaxngAttribute ReadAttributePattern ()
613 RelaxngAttribute attr = new RelaxngAttribute ();
616 if (MoveToFirstAttribute ()) {
618 if (NamespaceURI != String.Empty)
621 case "datatypeLibrary":
626 throw new RelaxngException ("Invalid attribute.");
628 } while (MoveToNextAttribute ());
632 string ns = GetSpaceStrippedAttribute ("ns", String.Empty);
634 // try to get name from attribute.
635 if (MoveToAttribute ("name", String.Empty)) {
636 // attr.NameClass = resolvedName (XmlConvert.VerifyName (Value.Trim ()), false);
637 RelaxngName nc = new RelaxngName ();
638 string name = XmlConvert.VerifyName (Value.Trim ());
639 if (name.IndexOf (':') > 0)
640 nc = resolvedName (name);
643 nc.Namespace = ns == null ? String.Empty : ns;
649 if (!IsEmptyElement) {
651 // read nameClass from content.
652 if (attr.NameClass == null)
653 attr.NameClass = ReadNameClass ();
655 if (NodeType == XmlNodeType.Element)
656 attr.Pattern = ReadPattern ();
658 expectEnd ("attribute");
662 if (attr.NameClass == null)
663 throw new RelaxngException ("Name class was not specified.");
667 private RelaxngGrammar ReadGrammarPattern ()
669 RelaxngGrammar grammar = new RelaxngGrammar ();
670 FillLocation (grammar);
671 grammar.DefaultNamespace = Reader.GetAttribute ("ns");
673 this.readGrammarIncludeContent (grammar.Starts, grammar.Defines, grammar.Divs, grammar.Includes);
674 expectEnd ("grammar");
679 private RelaxngRef ReadRefPattern ()
681 RelaxngRef r = new RelaxngRef ();
684 r.Name = GetNameAttribute ();
685 if (!IsEmptyElement) {
694 private RelaxngExternalRef ReadExternalRefPattern ()
696 RelaxngExternalRef r = new RelaxngExternalRef ();
698 expect ("externalRef");
699 string href = GetSpaceStrippedAttribute ("href", String.Empty);
701 throw new RelaxngException ("Required attribute href was not found.");
702 XmlResolver res = resolver != null ? resolver : new XmlUrlResolver ();
703 r.Href = res.ResolveUri (BaseURI != null ? new Uri (BaseURI) : null, href).AbsoluteUri;
704 r.NSContext = ContextNamespace;
705 if (!IsEmptyElement) {
707 expectEnd ("externalRef");
714 private RelaxngParentRef ReadParentRefPattern ()
716 RelaxngParentRef r = new RelaxngParentRef ();
718 expect ("parentRef");
719 r.Name = GetNameAttribute ();
720 if (!IsEmptyElement) {
722 expectEnd ("parentRef");
729 private RelaxngEmpty ReadEmptyPattern ()
733 if (MoveToFirstAttribute ()) {
735 if (NamespaceURI == String.Empty && LocalName != "datatypeLibrary")
736 throw new RelaxngException ("Invalid attribute.");
737 } while (MoveToNextAttribute ());
741 if (!IsEmptyElement) {
748 RelaxngEmpty empty = new RelaxngEmpty ();
749 FillLocation (empty);
753 private RelaxngText ReadTextPattern ()
757 if (MoveToFirstAttribute ()) {
759 if (NamespaceURI == String.Empty && LocalName != "datatypeLibrary")
760 throw new RelaxngException ("Invalid attribute.");
761 } while (MoveToNextAttribute ());
765 if (!IsEmptyElement) {
772 RelaxngText t = new RelaxngText ();
777 private RelaxngData ReadDataPattern ()
779 RelaxngData data = new RelaxngData ();
783 data.Type = GetSpaceStrippedAttribute ("type", String.Empty);
784 if (data.Type == null)
785 throw new RelaxngException ("Attribute type is required.");
786 data.DatatypeLibrary = DatatypeLibrary;
788 if (MoveToFirstAttribute ()) {
790 if (NamespaceURI != String.Empty)
793 case "datatypeLibrary":
797 throw new RelaxngException ("Invalid attribute.");
799 } while (MoveToNextAttribute ());
803 if (!IsEmptyElement) {
805 while (Name == "param") {
806 data.ParamList.Add (ReadParam ());
808 if (LocalName == "except")
809 data.Except = ReadPatternExcept ();
817 private RelaxngValue ReadValuePattern ()
819 RelaxngValue v = new RelaxngValue ();
823 if (MoveToFirstAttribute ()) {
825 if (NamespaceURI != String.Empty)
828 case "datatypeLibrary":
833 throw new RelaxngException ("Invalid attribute.");
835 } while (MoveToNextAttribute ());
839 if (MoveToAttribute ("type")) {
840 v.Type = Value.Trim ();
841 v.DatatypeLibrary = DatatypeLibrary;
844 v.DatatypeLibrary = "";
846 // v.Namespace = GetSpaceStrippedAttribute ("ns", String.Empty);
848 if (IsEmptyElement) {
849 v.Value = String.Empty;
852 v.Value = ReadString ();
859 private RelaxngList ReadListPattern ()
861 RelaxngList list = new RelaxngList ();
870 private RelaxngOneOrMore ReadOneOrMorePattern ()
872 RelaxngOneOrMore o = new RelaxngOneOrMore ();
874 expect ("oneOrMore");
877 expectEnd ("oneOrMore");
881 private RelaxngZeroOrMore ReadZeroOrMorePattern ()
883 RelaxngZeroOrMore o = new RelaxngZeroOrMore ();
885 expect ("zeroOrMore");
888 expectEnd ("zeroOrMore");
892 private RelaxngOptional ReadOptionalPattern ()
894 RelaxngOptional o = new RelaxngOptional ();
899 expectEnd ("optional");
903 private RelaxngMixed ReadMixedPattern ()
905 RelaxngMixed o = new RelaxngMixed ();
914 private RelaxngGroup ReadGroupPattern ()
916 RelaxngGroup g = new RelaxngGroup ();
925 private RelaxngInterleave ReadInterleavePattern ()
927 RelaxngInterleave i = new RelaxngInterleave ();
929 expect ("interleave");
932 expectEnd ("interleave");
936 private RelaxngChoice ReadChoicePattern ()
938 RelaxngChoice c = new RelaxngChoice ();
943 expectEnd ("choice");
947 private RelaxngNotAllowed ReadNotAllowedPattern ()
949 expect ("notAllowed");
950 if (!IsEmptyElement) {
952 expectEnd ("notAllowed");
956 RelaxngNotAllowed na = new RelaxngNotAllowed ();