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 bool skipExternal
= true;
64 // ArrayList annotationNamespaces = new ArrayList ();
67 public RelaxngReader (XmlReader reader
)
72 public RelaxngReader (XmlReader reader
, string ns
)
73 : this (reader
, ns
, new XmlUrlResolver ())
77 public RelaxngReader (XmlReader reader
, string ns
, XmlResolver resolver
)
78 // : base (grammarForRelaxng == null ? reader : new RelaxngValidatingReader (reader, grammarForRelaxng))
81 this.resolver
= resolver
;
82 if (Reader
.ReadState
== ReadState
.Initial
)
85 string nsval
= GetSpaceStrippedAttribute ("ns", String
.Empty
);
88 nsStack
.Push (nsval
== null ? String
.Empty
: nsval
);
89 string dtlib
= GetSpaceStrippedAttribute ("datatypeLibrary", String
.Empty
);
90 datatypeLibraryStack
.Push (dtlib
!= null ?
91 dtlib
: String
.Empty
);
94 public XmlResolver XmlResolver
{
95 set { resolver = value; }
98 internal XmlResolver Resolver
{
99 get { return resolver; }
102 private void FillLocation (RelaxngElementBase el
)
104 el
.BaseUri
= BaseURI
;
105 IXmlLineInfo li
= this as IXmlLineInfo
;
106 el
.LineNumber
= li
!= null ? li
.LineNumber
: 0;
107 el
.LinePosition
= li
!= null ? li
.LinePosition
: 0;
111 public void AddAnnotationNamespace (string ns)
113 if (!annotationNamespaces.Contains (ns))
114 annotationNamespaces.Add (ns);
119 public override bool Read ()
121 bool skipRead
= false;
125 if (IsEmptyElement
|| NodeType
== XmlNodeType
.EndElement
) { // this should be done here
127 datatypeLibraryStack
.Pop ();
135 case XmlNodeType
.ProcessingInstruction
:
136 case XmlNodeType
.Comment
:
137 case XmlNodeType
.EntityReference
:
139 case XmlNodeType
.Whitespace
:
140 // Skip whitespaces except for data and param.
141 case XmlNodeType
.SignificantWhitespace
:
142 if (LocalName
!= "value" && LocalName
!= "param") {
148 case XmlNodeType
.Element
:
149 case XmlNodeType
.EndElement
:
152 if (NamespaceURI
!= RelaxngGrammar
.NamespaceURI
) {
163 } while (!Reader
.EOF
&& loop
);
166 case XmlNodeType
.Element
:
167 if (MoveToAttribute ("ns")) {
168 nsStack
.Push (Value
.Trim ());
172 nsStack
.Push (ContextNamespace
);
174 if (MoveToAttribute ("datatypeLibrary")) {
175 string uriString
= Value
.Trim ();
176 if (uriString
.Length
== 0)
177 datatypeLibraryStack
.Push (String
.Empty
);
180 Uri uri
= new Uri (uriString
);
181 // MS.NET Uri is too lamespec
182 datatypeLibraryStack
.Push (uri
.ToString ());
183 } catch (UriFormatException ex
) {
184 throw new RelaxngException (ex
.Message
, ex
);
190 datatypeLibraryStack
.Push (DatatypeLibrary
);
199 public string ContextNamespace
{
201 if (nsStack
.Count
== 0)
202 // It happens only on initialization.
204 return nsStack
.Peek () as string;
208 public string DatatypeLibrary
{
210 if (datatypeLibraryStack
.Count
== 0)
211 // It happens only on initialization.
213 return datatypeLibraryStack
.Peek () as string;
218 private void expect (string name
)
220 if (NamespaceURI
!= RelaxngGrammar
.NamespaceURI
)
221 throw new RelaxngException (String
.Format ("Invalid document: expected namespace {0} but found {1}", RelaxngGrammar
.NamespaceURI
, NamespaceURI
));
222 else if (LocalName
!= name
)
223 throw new RelaxngException (String
.Format ("Invalid document: expected local name {0} but found {1}", name
, LocalName
));
226 private void expectEnd (string name
)
228 if (NodeType
!= XmlNodeType
.EndElement
)
229 throw new RelaxngException (String
.Format ("Expected EndElement but found {0}.", NodeType
));
235 // Other than name class and pattern.
236 private RelaxngStart
ReadStart ()
238 RelaxngStart s
= new RelaxngStart ();
242 if (MoveToFirstAttribute ()) {
244 if (NamespaceURI
!= String
.Empty
)
247 case "datatypeLibrary":
251 throw new RelaxngException ("Invalid attribute.");
253 } while (MoveToNextAttribute ());
257 if (MoveToAttribute ("combine")) {
258 s
.Combine
= Value
.Trim ();
259 if (s
.Combine
!= "choice" && s
.Combine
!= "interleave")
260 throw new RelaxngException ("Invalid combine attribute: " + s
.Combine
);
265 s
.Pattern
= ReadPattern ();
270 private string GetNameAttribute ()
272 string name
= GetSpaceStrippedAttribute ("name", String
.Empty
);
274 throw new RelaxngException ("Required attribute name is not found.");
275 return XmlConvert
.VerifyNCName (name
);
278 private string GetSpaceStrippedAttribute (string name
, string ns
)
280 string v
= GetAttribute (name
, ns
);
281 return v
!= null ? v
.Trim () : null;
284 private RelaxngDefine
ReadDefine ()
286 RelaxngDefine def
= new RelaxngDefine ();
289 def
.Name
= GetNameAttribute ();
290 def
.Combine
= GetSpaceStrippedAttribute ("combine", String
.Empty
);
293 while (NodeType
== XmlNodeType
.Element
)
294 def
.Patterns
.Add (ReadPattern ());
295 expectEnd ("define");
299 private RelaxngParam
ReadParam ()
301 RelaxngParam p
= new RelaxngParam ();
304 p
.Name
= GetNameAttribute ();
305 p
.Value
= ReadString ().Trim ();
310 // NameClass reader (only if it is element-style.)
311 private RelaxngNameClass
ReadNameClass ()
315 return ReadNameClassName ();
317 return ReadNameClassAnyName ();
319 return ReadNameClassNsName ();
321 return ReadNameClassChoice ();
323 throw new RelaxngException ("Invalid name class: " + LocalName
);
326 private RelaxngName
ReadNameClassName ()
328 string name
= ReadString ().Trim ();
329 RelaxngName rName
= resolvedName (name
);
334 private RelaxngAnyName
ReadNameClassAnyName ()
336 RelaxngAnyName an
= new RelaxngAnyName ();
338 if (!IsEmptyElement
) {
340 if (NodeType
== XmlNodeType
.EndElement
) {
345 an
.Except
= new RelaxngExceptNameClass ();
346 FillLocation (an
.Except
);
347 while (NodeType
== XmlNodeType
.Element
)
348 an
.Except
.Names
.Add (
350 expectEnd ("except");
352 expectEnd ("anyName");
358 private RelaxngNsName
ReadNameClassNsName ()
360 RelaxngNsName nn
= new RelaxngNsName ();
362 nn
.Namespace
= this.ContextNamespace
;
363 if (!IsEmptyElement
) {
365 if (NodeType
== XmlNodeType
.EndElement
) {
370 nn
.Except
= ReadNameClassExcept ();//new RelaxngExceptNameClass ();
371 FillLocation (nn
.Except
);
373 expectEnd ("nsName");
379 private RelaxngNameChoice
ReadNameClassChoice ()
381 RelaxngNameChoice nc
= new RelaxngNameChoice ();
384 throw new RelaxngException ("Name choice must have at least one name class.");
387 while (NodeType
!= XmlNodeType
.EndElement
) {
388 nc
.Children
.Add (ReadNameClass ());
390 if (nc
.Children
.Count
== 0)
391 throw new RelaxngException ("Name choice must have at least one name class.");
393 expectEnd ("choice");
397 private RelaxngExceptNameClass
ReadNameClassExcept ()
399 RelaxngExceptNameClass x
= new RelaxngExceptNameClass ();
402 throw new RelaxngException ("Name choice must have at least one name class.");
405 while (NodeType
!= XmlNodeType
.EndElement
)
406 x
.Names
.Add (ReadNameClass ());
407 if (x
.Names
.Count
== 0)
408 throw new RelaxngException ("Name choice must have at least one name class.");
410 expectEnd ("except");
416 public RelaxngPattern
ReadPattern ()
418 while (NodeType
!= XmlNodeType
.Element
)
420 throw new RelaxngException ("RELAX NG pattern did not appear.");
424 return ReadElementPattern ();
426 return ReadAttributePattern ();
428 return ReadGroupPattern ();
430 return ReadInterleavePattern ();
432 return ReadChoicePattern ();
434 return ReadOptionalPattern ();
436 return ReadZeroOrMorePattern ();
438 return ReadOneOrMorePattern ();
440 return ReadListPattern ();
442 return ReadMixedPattern ();
444 return ReadRefPattern ();
446 return ReadParentRefPattern ();
448 return ReadEmptyPattern ();
450 return ReadTextPattern ();
452 return ReadDataPattern ();
454 return ReadValuePattern ();
456 return ReadNotAllowedPattern ();
458 return ReadExternalRefPattern ();
460 return ReadGrammarPattern ();
462 throw new RelaxngException ("Non-supported pattern specification: " + LocalName
);
465 private void ReadPatterns (RelaxngSingleContentPattern el
)
468 el
.Patterns
.Add (ReadPattern ());
469 } while (NodeType
== XmlNodeType
.Element
);
472 private void ReadPatterns (RelaxngBinaryContentPattern el
)
475 el
.Patterns
.Add (ReadPattern ());
476 } while (NodeType
== XmlNodeType
.Element
);
479 private RelaxngExcept
ReadPatternExcept ()
481 RelaxngExcept x
= new RelaxngExcept ();
484 throw new RelaxngException ("'except' must have at least one pattern.");
486 while (NodeType
!= XmlNodeType
.EndElement
)
487 x
.Patterns
.Add (ReadPattern ());
488 if (x
.Patterns
.Count
== 0)
489 throw new RelaxngException ("'except' must have at least one pattern.");
491 expectEnd ("except");
495 private RelaxngInclude
ReadInclude ()
497 RelaxngInclude i
= new RelaxngInclude ();
500 i
.NSContext
= ContextNamespace
;
501 string href
= GetSpaceStrippedAttribute ("href", String
.Empty
);
503 throw new RelaxngException ("Required attribute href was not found.");
504 XmlResolver res
= resolver
!= null ? resolver
: new XmlUrlResolver ();
505 i
.Href
= res
.ResolveUri (BaseURI
!= null ? new Uri (BaseURI
) : null, href
).AbsoluteUri
;
506 if (!IsEmptyElement
) {
508 this.readGrammarIncludeContent (i
.Starts
, i
.Defines
, i
.Divs
, null);
509 expectEnd ("include");
516 private void readGrammarIncludeContent (IList starts
, IList defines
, IList divs
, IList includes
)
518 while (NodeType
== XmlNodeType
.Element
) {
521 starts
.Add (ReadStart ());
524 defines
.Add (ReadDefine ());
527 divs
.Add (ReadDiv (includes
!= null));
530 if (includes
!= null)
531 includes
.Add (ReadInclude ());
533 throw new RelaxngException ("Unexpected content: " + Name
);
536 throw new RelaxngException ("Unexpected content: " + Name
);
541 private RelaxngDiv
ReadDiv (bool allowIncludes
)
544 RelaxngDiv div
= new RelaxngDiv ();
546 if (!IsEmptyElement
) {
548 readGrammarIncludeContent (div
.Starts
, div
.Defines
, div
.Divs
, div
.Includes
);
556 private RelaxngName
resolvedName (string nameSpec
)
558 int colonAt
= nameSpec
.IndexOf (':');
559 string prefix
= (colonAt
< 0) ? "" : nameSpec
.Substring (0, colonAt
);
560 string local
= (colonAt
< 0) ? nameSpec
: nameSpec
.Substring (colonAt
+ 1, nameSpec
.Length
- colonAt
- 1);
561 string uri
= ContextNamespace
;
564 uri
= LookupNamespace (prefix
);
566 throw new RelaxngException ("Undeclared prefix in name component: " + nameSpec
);
568 RelaxngName n
= new RelaxngName (local
, uri
);
573 private RelaxngElement
ReadElementPattern ()
575 RelaxngElement el
= new RelaxngElement ();
578 if (MoveToFirstAttribute ()) {
580 if (NamespaceURI
!= String
.Empty
)
583 case "datatypeLibrary":
588 throw new RelaxngException ("Invalid attribute.");
590 } while (MoveToNextAttribute ());
594 // try to get name from attribute.
595 if (MoveToAttribute ("name"))
596 el
.NameClass
= resolvedName (XmlConvert
.VerifyName (Value
.Trim ()));
600 // read nameClass from content.
601 if (el
.NameClass
== null)
602 el
.NameClass
= ReadNameClass ();
605 this.ReadPatterns (el
);
607 expectEnd ("element");
609 if (el
.NameClass
== null)
610 throw new RelaxngException ("Name class was not specified.");
614 private RelaxngAttribute
ReadAttributePattern ()
616 RelaxngAttribute attr
= new RelaxngAttribute ();
619 if (MoveToFirstAttribute ()) {
621 if (NamespaceURI
!= String
.Empty
)
624 case "datatypeLibrary":
629 throw new RelaxngException ("Invalid attribute.");
631 } while (MoveToNextAttribute ());
635 string ns
= GetSpaceStrippedAttribute ("ns", String
.Empty
);
637 // try to get name from attribute.
638 if (MoveToAttribute ("name", String
.Empty
)) {
639 // attr.NameClass = resolvedName (XmlConvert.VerifyName (Value.Trim ()), false);
640 RelaxngName nc
= new RelaxngName ();
641 string name
= XmlConvert
.VerifyName (Value
.Trim ());
642 if (name
.IndexOf (':') > 0)
643 nc
= resolvedName (name
);
646 nc
.Namespace
= ns
== null ? String
.Empty
: ns
;
652 if (!IsEmptyElement
) {
654 // read nameClass from content.
655 if (attr
.NameClass
== null)
656 attr
.NameClass
= ReadNameClass ();
658 if (NodeType
== XmlNodeType
.Element
)
659 attr
.Pattern
= ReadPattern ();
661 expectEnd ("attribute");
665 if (attr
.NameClass
== null)
666 throw new RelaxngException ("Name class was not specified.");
670 private RelaxngGrammar
ReadGrammarPattern ()
672 RelaxngGrammar grammar
= new RelaxngGrammar ();
673 FillLocation (grammar
);
674 grammar
.DefaultNamespace
= Reader
.GetAttribute ("ns");
676 this.readGrammarIncludeContent (grammar
.Starts
, grammar
.Defines
, grammar
.Divs
, grammar
.Includes
);
677 expectEnd ("grammar");
682 private RelaxngRef
ReadRefPattern ()
684 RelaxngRef r
= new RelaxngRef ();
687 r
.Name
= GetNameAttribute ();
688 if (!IsEmptyElement
) {
697 private RelaxngExternalRef
ReadExternalRefPattern ()
699 RelaxngExternalRef r
= new RelaxngExternalRef ();
701 expect ("externalRef");
702 string href
= GetSpaceStrippedAttribute ("href", String
.Empty
);
704 throw new RelaxngException ("Required attribute href was not found.");
705 XmlResolver res
= resolver
!= null ? resolver
: new XmlUrlResolver ();
706 r
.Href
= res
.ResolveUri (BaseURI
!= null ? new Uri (BaseURI
) : null, href
).AbsoluteUri
;
707 r
.NSContext
= ContextNamespace
;
708 if (!IsEmptyElement
) {
710 expectEnd ("externalRef");
717 private RelaxngParentRef
ReadParentRefPattern ()
719 RelaxngParentRef r
= new RelaxngParentRef ();
721 expect ("parentRef");
722 r
.Name
= GetNameAttribute ();
723 if (!IsEmptyElement
) {
725 expectEnd ("parentRef");
732 private RelaxngEmpty
ReadEmptyPattern ()
736 if (MoveToFirstAttribute ()) {
738 if (NamespaceURI
== String
.Empty
&& LocalName
!= "datatypeLibrary")
739 throw new RelaxngException ("Invalid attribute.");
740 } while (MoveToNextAttribute ());
744 if (!IsEmptyElement
) {
751 RelaxngEmpty empty
= new RelaxngEmpty ();
752 FillLocation (empty
);
756 private RelaxngText
ReadTextPattern ()
760 if (MoveToFirstAttribute ()) {
762 if (NamespaceURI
== String
.Empty
&& LocalName
!= "datatypeLibrary")
763 throw new RelaxngException ("Invalid attribute.");
764 } while (MoveToNextAttribute ());
768 if (!IsEmptyElement
) {
775 RelaxngText t
= new RelaxngText ();
780 private RelaxngData
ReadDataPattern ()
782 RelaxngData data
= new RelaxngData ();
786 data
.Type
= GetSpaceStrippedAttribute ("type", String
.Empty
);
787 if (data
.Type
== null)
788 throw new RelaxngException ("Attribute type is required.");
789 data
.DatatypeLibrary
= DatatypeLibrary
;
791 if (MoveToFirstAttribute ()) {
793 if (NamespaceURI
!= String
.Empty
)
796 case "datatypeLibrary":
800 throw new RelaxngException ("Invalid attribute.");
802 } while (MoveToNextAttribute ());
806 if (!IsEmptyElement
) {
808 while (Name
== "param") {
809 data
.ParamList
.Add (ReadParam ());
811 if (LocalName
== "except")
812 data
.Except
= ReadPatternExcept ();
820 private RelaxngValue
ReadValuePattern ()
822 RelaxngValue v
= new RelaxngValue ();
826 if (MoveToFirstAttribute ()) {
828 if (NamespaceURI
!= String
.Empty
)
831 case "datatypeLibrary":
836 throw new RelaxngException ("Invalid attribute.");
838 } while (MoveToNextAttribute ());
842 if (MoveToAttribute ("type")) {
843 v
.Type
= Value
.Trim ();
844 v
.DatatypeLibrary
= DatatypeLibrary
;
847 v
.DatatypeLibrary
= "";
849 // v.Namespace = GetSpaceStrippedAttribute ("ns", String.Empty);
851 if (IsEmptyElement
) {
852 v
.Value
= String
.Empty
;
855 v
.Value
= ReadString ();
862 private RelaxngList
ReadListPattern ()
864 RelaxngList list
= new RelaxngList ();
873 private RelaxngOneOrMore
ReadOneOrMorePattern ()
875 RelaxngOneOrMore o
= new RelaxngOneOrMore ();
877 expect ("oneOrMore");
880 expectEnd ("oneOrMore");
884 private RelaxngZeroOrMore
ReadZeroOrMorePattern ()
886 RelaxngZeroOrMore o
= new RelaxngZeroOrMore ();
888 expect ("zeroOrMore");
891 expectEnd ("zeroOrMore");
895 private RelaxngOptional
ReadOptionalPattern ()
897 RelaxngOptional o
= new RelaxngOptional ();
902 expectEnd ("optional");
906 private RelaxngMixed
ReadMixedPattern ()
908 RelaxngMixed o
= new RelaxngMixed ();
917 private RelaxngGroup
ReadGroupPattern ()
919 RelaxngGroup g
= new RelaxngGroup ();
928 private RelaxngInterleave
ReadInterleavePattern ()
930 RelaxngInterleave i
= new RelaxngInterleave ();
932 expect ("interleave");
935 expectEnd ("interleave");
939 private RelaxngChoice
ReadChoicePattern ()
941 RelaxngChoice c
= new RelaxngChoice ();
946 expectEnd ("choice");
950 private RelaxngNotAllowed
ReadNotAllowedPattern ()
952 expect ("notAllowed");
953 if (!IsEmptyElement
) {
955 expectEnd ("notAllowed");
959 RelaxngNotAllowed na
= new RelaxngNotAllowed ();
964 public override string ReadString ()
966 skipExternal
= false;
967 string s
= base.ReadString ();