2 // Commons.Xml.Relaxng.Derivative.RdpPatterns.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;
37 using Commons.Xml.Relaxng;
39 using LabelList = System.Collections.Hashtable;
42 namespace Commons.Xml.Relaxng.Derivative
44 public delegate RdpPattern RdpApplyAfterHandler (RdpPattern p);
47 public abstract class RdpPattern
49 internal bool nullableComputed;
50 internal bool isNullable;
51 Hashtable patternPool;
53 internal string debug ()
55 return RdpUtil.DebugRdpPattern (this, new Hashtable ());
58 public abstract RelaxngPatternType PatternType { get; }
60 public abstract RdpContentType ContentType { get; }
62 private Hashtable setupTable (Type type, RdpPattern p)
64 if (patternPool == null) // could be null for RdpElement etc.
65 patternPool = new Hashtable ();
67 Hashtable typePool = (Hashtable) patternPool [type];
68 if (typePool == null) {
69 typePool = new Hashtable ();
70 patternPool [type] = typePool;
72 Hashtable pTable = (Hashtable) typePool [p];
74 pTable = new Hashtable ();
75 typePool [p] = pTable;
80 internal RdpFlip MakeFlip (RdpBinaryFunction func, RdpPattern p)
82 // Though this method takes function argument, all
83 // p1 callers have different pattern types, so we don't
84 // have to distinguish tables by func.
86 Hashtable table = patternPool [func] as Hashtable;
88 table = new Hashtable ();
89 patternPool [func] = table;
91 RdpFlip f = table [p] as RdpFlip;
94 f = new RdpFlip (func, p);
99 public RdpChoice MakeChoice (RdpPattern p1, RdpPattern p2)
101 Hashtable p1Table = setupTable (typeof (RdpChoice), p1);
102 if (p1Table [p2] == null) {
103 RdpChoice c = new RdpChoice (p1, p2);
104 c.setInternTable (this.patternPool);
107 return (RdpChoice) p1Table [p2];
110 public RdpPattern MakeGroup (RdpPattern p1, RdpPattern p2)
112 Hashtable p1Table = setupTable (typeof (RdpGroup), p1);
113 if (p1Table [p2] == null) {
114 RdpGroup g = new RdpGroup (p1, p2);
115 g.setInternTable (this.patternPool);
118 return (RdpGroup) p1Table [p2];
121 public RdpInterleave MakeInterleave (RdpPattern p1, RdpPattern p2)
123 Hashtable p1Table = setupTable (typeof (RdpInterleave), p1);
124 if (p1Table [p2] == null) {
125 RdpInterleave i = new RdpInterleave (p1, p2);
126 i.setInternTable (this.patternPool);
129 return (RdpInterleave) p1Table [p2];
132 public RdpAfter MakeAfter (RdpPattern p1, RdpPattern p2)
134 Hashtable p1Table = setupTable (typeof (RdpAfter), p1);
135 if (p1Table [p2] == null) {
136 RdpAfter a = new RdpAfter (p1, p2);
137 a.setInternTable (this.patternPool);
140 return (RdpAfter) p1Table [p2];
143 public RdpOneOrMore MakeOneOrMore (RdpPattern p)
145 Hashtable pTable = (Hashtable) patternPool [typeof (RdpOneOrMore)];
146 if (pTable == null) {
147 pTable = new Hashtable ();
148 patternPool [typeof (RdpOneOrMore)] = pTable;
150 if (pTable [p] == null) {
151 RdpOneOrMore oom = new RdpOneOrMore (p);
152 oom.setInternTable (patternPool);
155 return (RdpOneOrMore) pTable [p];
158 internal void setInternTable (Hashtable ht)
160 if (this.patternPool != null)
162 this.patternPool = ht;
164 Hashtable pt = ht [GetType ()] as Hashtable;
166 pt = new Hashtable ();
167 ht [GetType ()] = pt;
170 RdpAbstractSingleContent single =
171 this as RdpAbstractSingleContent;
172 if (single != null) {
173 if (pt [single.Child] == null) {
174 pt [single.Child] = this;
175 single.Child.setInternTable (ht);
180 RdpAbstractBinary binary =
181 this as RdpAbstractBinary;
182 if (binary != null) {
183 Hashtable lTable = setupTable (GetType (), binary.LValue);
184 if (lTable [binary.RValue] == null) {
185 lTable [binary.RValue] = this;
186 binary.LValue.setInternTable (ht);
187 binary.RValue.setInternTable (ht);
192 // For rest patterns, only check recursively, without pooling.
193 RdpAttribute attr = this as RdpAttribute;
195 attr.Children.setInternTable (ht);
198 RdpElement el = this as RdpElement;
200 el.Children.setInternTable (ht);
203 RdpDataExcept dex= this as RdpDataExcept;
205 dex.Except.setInternTable (ht);
209 switch (PatternType) {
210 case RelaxngPatternType.Empty:
211 case RelaxngPatternType.NotAllowed:
212 case RelaxngPatternType.Text:
213 case RelaxngPatternType.Data:
214 case RelaxngPatternType.Value:
218 #if REPLACE_IN_ADVANCE
219 throw new InvalidOperationException ();
223 internal abstract void MarkReachableDefs ();
225 internal abstract void CheckConstraints (bool attribute, bool oneOrMore, bool oneOrMoreGroup, bool oneOrMoreInterleave, bool list, bool dataExcept);
227 // This method is to detect text pattern inside interleave child.
228 internal abstract bool ContainsText ();
230 internal virtual RdpPattern ExpandRef (Hashtable defs)
235 internal virtual RdpPattern ReduceEmptyAndNotAllowed (ref bool result, Hashtable visited)
240 public abstract bool Nullable { get; }
242 // fills QName collection
243 public void GetLabels (LabelList elements, LabelList attributes)
245 GetLabels (elements, attributes, false);
248 public abstract void GetLabels (LabelList elements, LabelList attributes, bool collectNameClass);
250 internal void AddNameLabel (LabelList names, RdpNameClass nc)
252 RdpName name = nc as RdpName;
254 XmlQualifiedName qname = new XmlQualifiedName (
255 name.LocalName, name.NamespaceURI);
256 names [qname] = qname;
259 RdpNameClassChoice choice = nc as RdpNameClassChoice;
260 if (choice != null) {
261 AddNameLabel (names, choice.LValue);
262 AddNameLabel (names, choice.RValue);
265 // For NsName and AnyName, do nothing.
269 public virtual RdpPattern TextDeriv (string s, XmlReader reader)
271 // This is an extension to JJC algorithm.
272 // Whitespace text are allowed except for Data and Value
273 // (their TextDeriv are overridden)
274 return Util.IsWhitespace (s) ? this : RdpNotAllowed.Instance;
278 public RdpPattern ChildDeriv (RdpChildNode child)
280 RdpTextChild tc = child as RdpTextChild;
281 // RdpElementChild ec = child as RdpElementChild;
283 return TextDeriv (tc.Text);
286 return StartTagOpenDeriv (ec.LocalName, ec.NamespaceURI)
287 .AttsDeriv (ec.Attributes)
288 .StartTagCloseDeriv ()
289 .ChildrenDeriv (ec.ChildNodes)
295 public RdpPattern ListDeriv (string [] list, int index, XmlReader reader)
297 return listDerivInternal (list, 0, reader);
300 private RdpPattern listDerivInternal (string [] list, int start, XmlReader reader)
302 if (list.Length <= start)
305 return this.TextDeriv (list [start], reader).listDerivInternal (list, start + 1, reader);
309 public virtual RdpPattern Choice (RdpPattern p)
311 if (p is RdpNotAllowed)
313 else if (this is RdpNotAllowed)
316 return MakeChoice (this, p);
320 public virtual RdpPattern Group (RdpPattern p)
322 if (p is RdpNotAllowed || this is RdpNotAllowed)
323 return RdpNotAllowed.Instance;
324 else if (p is RdpEmpty)
326 else if (this is RdpEmpty)
329 return MakeGroup (this, p);
332 // Interleave(this, p)
333 public virtual RdpPattern Interleave (RdpPattern p)
335 if (p is RdpNotAllowed || this is RdpNotAllowed)
336 return RdpNotAllowed.Instance;
337 else if (p is RdpEmpty)
339 else if (this is RdpEmpty)
342 return MakeInterleave (this, p);
346 public virtual RdpPattern After (RdpPattern p)
348 if (this is RdpNotAllowed || p is RdpNotAllowed)
349 return RdpNotAllowed.Instance;
351 return MakeAfter (this, p);
355 // applyAfter((f, p1=this), p2)
356 public virtual RdpPattern ApplyAfter (RdpApplyAfterHandler h)
358 return RdpNotAllowed.Instance;
361 // startTagOpenDeriv (this, qname)
362 // startTagOpenDeriv _ qn = NotAllowed (default)
363 public virtual RdpPattern StartTagOpenDeriv (string name, string ns)
365 return RdpNotAllowed.Instance;
368 // attDeriv(ctx, this, att)
369 // attDeriv _ _ _ = NotAllowed
370 public virtual RdpPattern AttDeriv (string name, string ns, string value, XmlReader reader)
372 return RdpNotAllowed.Instance;
375 public bool ValueMatch (string s, XmlReader reader)
377 return TextDeriv (s, reader).Nullable;
380 public virtual RdpPattern StartTagCloseDeriv ()
386 public RdpPattern ChildrenDeriv (RdpChildNodes children)
388 return childrenDerivInternal (children, 0);
391 RdpPattern childrenDerivInternal (RdpChildNodes children, int start)
393 if (children.Count == 0) {
394 // childrenDeriv cx p []
395 RdpChildNodes c = new RdpChildNodes ();
396 c.Add (new RdpTextChild (String.Empty));
397 return ChildrenDeriv (c);
398 } else if (children.Count == 1 && children [0] is RdpTextChild) {
399 // childrenDeriv cx p [(TextNode s)]
400 RdpTextChild tc = children [0] as RdpTextChild;
401 RdpPattern p1 = ChildDeriv (tc);
402 return RdpUtil.Whitespace (tc.Text) ?
403 RdpUtil.Choice (this, p1) : p1;
405 // childrenDeriv cx p children
406 return stripChildrenDerivInternal (children, start);
409 RdpPattern stripChildrenDerivInternal (RdpChildNodes children, int start)
411 if (children.Count == start)
414 RdpChildNode firstChild =
415 children [start] as RdpChildNode;
417 (firstChild.IsNonWhitespaceText) ?
418 this : ChildDeriv (firstChild);
419 return p.childrenDerivInternal (children, start + 1);
424 public RdpPattern OneOrMore ()
426 if (PatternType == RelaxngPatternType.NotAllowed)
427 return RdpNotAllowed.Instance;
429 return MakeOneOrMore (this);
432 public virtual RdpPattern EndTagDeriv ()
434 return RdpNotAllowed.Instance;
440 public class RdpEmpty : RdpPattern
442 public RdpEmpty () {}
445 instance = new RdpEmpty ();
448 public override bool Nullable {
452 static RdpEmpty instance;
453 public static RdpEmpty Instance {
454 get { return instance; }
457 public override RelaxngPatternType PatternType {
458 get { return RelaxngPatternType.Empty; }
461 public override RdpContentType ContentType {
462 get { return RdpContentType.Empty; }
465 public override void GetLabels (LabelList elements, LabelList attributes, bool collectNameClass)
470 internal override void MarkReachableDefs ()
475 internal override void CheckConstraints (bool attribute, bool oneOrMore, bool oneOrMoreGroup, bool oneOrMoreInterleave, bool list, bool dataExcept)
478 throw new RelaxngException ("empty cannot appear under except of a data pattern.");
481 internal override bool ContainsText()
488 public class RdpNotAllowed : RdpPattern
490 public RdpNotAllowed () {}
491 static RdpNotAllowed ()
493 instance = new RdpNotAllowed ();
496 static RdpNotAllowed instance;
497 public static RdpNotAllowed Instance {
498 get { return instance; }
501 public override bool Nullable {
502 get { return false; }
505 public override RdpPattern ApplyAfter (RdpApplyAfterHandler h)
507 return RdpNotAllowed.Instance;
510 public override RelaxngPatternType PatternType {
511 get { return RelaxngPatternType.NotAllowed; }
514 public override RdpContentType ContentType {
515 get { return RdpContentType.Empty; }
518 internal override void MarkReachableDefs ()
523 internal override void CheckConstraints (bool attribute, bool oneOrMore, bool oneOrMoreGroup, bool oneOrMoreInterleave, bool list, bool dataExcept)
528 internal override bool ContainsText()
533 public override void GetLabels (LabelList elements, LabelList attributes, bool collectNameClass)
535 // FIXME: Supposed to clear something here?
540 public class RdpText : RdpPattern
542 static RdpText instance;
543 public static RdpText Instance {
544 get { return instance; }
550 instance = new RdpText ();
553 public override bool Nullable {
557 public override RelaxngPatternType PatternType {
558 get { return RelaxngPatternType.Text; }
561 public override RdpContentType ContentType {
562 get { return RdpContentType.Complex; }
565 public override RdpPattern TextDeriv (string s, XmlReader reader)
570 internal override void MarkReachableDefs ()
575 internal override void CheckConstraints (bool attribute, bool oneOrMore, bool oneOrMoreGroup, bool oneOrMoreInterleave, bool list, bool dataExcept)
578 throw new RelaxngException ("text is not allowed under a list.");
580 throw new RelaxngException ("text is not allowed under except of a list.");
583 internal override bool ContainsText()
588 public override void GetLabels (LabelList elements, LabelList attributes, bool collectNameClass)
595 public abstract class RdpAbstractBinary : RdpPattern
597 public RdpAbstractBinary (RdpPattern l, RdpPattern r)
604 public RdpPattern LValue {
610 public RdpPattern RValue {
615 RdpContentType computedContentType = RdpContentType.Invalid;
616 public override RdpContentType ContentType {
618 if (computedContentType == RdpContentType.Invalid) {
619 if (l.ContentType == RdpContentType.Empty)
620 computedContentType = r.ContentType;
621 else if (r.ContentType == RdpContentType.Empty)
622 computedContentType = l.ContentType;
623 else if ((l.ContentType & RdpContentType.Simple) != 0 || ((r.ContentType & RdpContentType.Simple) != 0))
624 throw new RelaxngException ("The content type of this group is invalid.");
626 computedContentType = RdpContentType.Complex;
628 return computedContentType;
633 internal override RdpPattern ExpandRef (Hashtable defs)
636 l = l.ExpandRef (defs);
637 r = r.ExpandRef (defs);
642 internal override RdpPattern ReduceEmptyAndNotAllowed (ref bool result, Hashtable visited)
644 if (visited.Contains (this))
646 visited.Add (this, this);
648 if (LValue.PatternType == RelaxngPatternType.NotAllowed ||
649 RValue.PatternType == RelaxngPatternType.NotAllowed) {
651 return RdpNotAllowed.Instance;
652 } else if (LValue.PatternType == RelaxngPatternType.Empty) {
654 return RValue.ReduceEmptyAndNotAllowed (ref result, visited);
655 } else if (RValue.PatternType == RelaxngPatternType.Empty) {
657 return LValue.ReduceEmptyAndNotAllowed (ref result, visited);
659 LValue = LValue.ReduceEmptyAndNotAllowed (ref result, visited);
660 RValue = RValue.ReduceEmptyAndNotAllowed (ref result, visited);
665 internal override void MarkReachableDefs ()
667 l.MarkReachableDefs ();
668 r.MarkReachableDefs ();
671 internal override bool ContainsText()
673 return l.ContainsText () || r.ContainsText ();
676 // 7.3 (group/interleave attribute names) and
677 // part of 7.4 (interleave element names)
678 // FIXME: Actually it should be done against the correct
679 // simplified grammar, expanding all refs.
680 internal void CheckNameOverlap (bool checkElements)
682 if (RdpUtil.NamesOverlap (LValue, RValue, checkElements))
683 throw new RelaxngException ("Duplicate attributes inside a group or an interleave is not allowed.");
689 public class RdpChoice : RdpAbstractBinary
691 public RdpChoice (RdpPattern l, RdpPattern r) : base (l, r)
695 public override bool Nullable {
697 if (!nullableComputed) {
699 LValue.Nullable || RValue.Nullable;
700 nullableComputed = true;
706 public override RelaxngPatternType PatternType {
707 get { return RelaxngPatternType.Choice; }
710 RdpContentType computedContentType = RdpContentType.Invalid;
711 public override RdpContentType ContentType {
713 if (computedContentType == RdpContentType.Invalid) {
714 if (LValue.ContentType == RdpContentType.Simple ||
715 RValue.ContentType == RdpContentType.Simple)
716 computedContentType = RdpContentType.Simple;
718 computedContentType = base.ContentType;
720 return computedContentType;
724 public override void GetLabels (LabelList elements, LabelList attributes, bool collectNameClass)
726 LValue.GetLabels (elements, attributes, collectNameClass);
727 RValue.GetLabels (elements, attributes, collectNameClass);
731 internal override RdpPattern ReduceEmptyAndNotAllowed (ref bool result, Hashtable visited)
733 if (visited.Contains (this))
735 visited.Add (this, this);
737 if (LValue.PatternType == RelaxngPatternType.NotAllowed &&
738 RValue.PatternType == RelaxngPatternType.NotAllowed) {
740 return RdpNotAllowed.Instance;
741 } else if (LValue.PatternType == RelaxngPatternType.NotAllowed) {
743 return RValue.ReduceEmptyAndNotAllowed (ref result, visited);
744 } else if (RValue.PatternType == RelaxngPatternType.NotAllowed) {
746 return LValue.ReduceEmptyAndNotAllowed (ref result, visited);
747 } else if (LValue.PatternType == RelaxngPatternType.Empty &&
748 RValue.PatternType == RelaxngPatternType.Empty) {
750 return RdpEmpty.Instance;
751 } else if (RValue.PatternType == RelaxngPatternType.Empty) {
753 RValue = LValue.ReduceEmptyAndNotAllowed (ref result, visited);
754 LValue = RdpEmpty.Instance;
757 LValue = LValue.ReduceEmptyAndNotAllowed (ref result, visited);
758 RValue = RValue.ReduceEmptyAndNotAllowed (ref result, visited);
763 public override RdpPattern TextDeriv (string s, XmlReader reader)
765 return LValue.TextDeriv (s, reader).Choice (RValue.TextDeriv (s, reader));
768 public override RdpPattern ApplyAfter (RdpApplyAfterHandler handler)
770 // return handler (LValue).Choice (handler (RValue));
771 return LValue.ApplyAfter (handler).Choice (RValue.ApplyAfter (handler));
774 public override RdpPattern StartTagOpenDeriv (string name, string ns)
777 return RdpUtil.Choice (
778 RdpUtil.StartTagOpenDeriv (LValue, qname),
779 RdpUtil.StartTagOpenDeriv (RValue, qname));
781 RdpPattern lDeriv = LValue.StartTagOpenDeriv (name, ns);
782 return lDeriv.Choice (RValue.StartTagOpenDeriv (name, ns));
786 // attDeriv cx (Choice p1 p2) att =
787 // choice (attDeriv cx p1 att) (attDeriv cx p2 att)
788 public override RdpPattern AttDeriv (string name, string ns, string value, XmlReader reader)
790 return LValue.AttDeriv (name, ns, value, reader)
791 .Choice (RValue.AttDeriv (name, ns, value, reader));
794 // startTagCloseDeriv (Choice p1 p2) =
795 // choice (startTagCloseDeriv p1) (startTagCloseDeriv p2)
796 public override RdpPattern StartTagCloseDeriv ()
798 return LValue.StartTagCloseDeriv ()
799 .Choice (RValue.StartTagCloseDeriv ());
802 public override RdpPattern EndTagDeriv ()
804 return LValue.EndTagDeriv ().Choice (RValue.EndTagDeriv ());
807 internal override void CheckConstraints (bool attribute, bool oneOrMore, bool oneOrMoreGroup, bool oneOrMoreInterleave, bool list, bool dataExcept)
809 LValue.CheckConstraints (attribute, oneOrMore, oneOrMoreGroup, oneOrMoreInterleave, list, dataExcept);
810 RValue.CheckConstraints (attribute, oneOrMore, oneOrMoreGroup, oneOrMoreInterleave, list, dataExcept);
815 public class RdpInterleave : RdpAbstractBinary
817 public RdpInterleave (RdpPattern l, RdpPattern r) : base (l, r)
821 public override bool Nullable {
823 if (!nullableComputed) {
825 LValue.Nullable && RValue.Nullable;
826 nullableComputed = true;
832 public override void GetLabels (LabelList elements, LabelList attributes, bool collectNameClass)
834 LValue.GetLabels (elements, attributes, collectNameClass);
835 RValue.GetLabels (elements, attributes, collectNameClass);
838 internal override RdpPattern ReduceEmptyAndNotAllowed (ref bool result, Hashtable visited)
840 if (visited.Contains (this))
842 visited.Add (this, this);
844 if (LValue.PatternType == RelaxngPatternType.NotAllowed ||
845 RValue.PatternType == RelaxngPatternType.NotAllowed) {
847 return RdpNotAllowed.Instance;
849 LValue = LValue.ReduceEmptyAndNotAllowed (ref result, visited);
850 RValue = RValue.ReduceEmptyAndNotAllowed (ref result, visited);
855 public override RdpPattern TextDeriv (string s, XmlReader reader)
857 return LValue.TextDeriv (s, reader).Interleave (RValue)
858 .Choice (LValue.Interleave (RValue.TextDeriv (s, reader)));
861 // => choice (applyAfter (flip interleave p2) (startTagOpenDeriv p1 qn)) (applyAfter (interleave p1) (startTagOpenDeriv p2 qn)
862 // => p1.startTagOpenDeriv(qn).applyAfter (flip interleave p2).choice (p2.startTagOpenDeriv(qn).applyAfter (interleave p1) )
863 public override RdpPattern StartTagOpenDeriv (string name, string ns)
865 RdpPattern handledL = LValue.StartTagOpenDeriv (name, ns);
866 RdpPattern handledR = RValue.StartTagOpenDeriv (name, ns);
867 RdpFlip flipL = MakeFlip (RdpUtil.InterleaveFunction, RValue);
868 RdpPattern choiceL = handledL.ApplyAfter (new RdpApplyAfterHandler (flipL.Apply));
869 RdpPattern choiceR = handledR.ApplyAfter (new RdpApplyAfterHandler (LValue.Interleave));
870 return choiceL.Choice (choiceR);
873 // attDeriv cx (Interleave p1 p2) att =
874 // choice (interleave (attDeriv cx p1 att) p2)
875 // (interleave p1 (attDeriv cx p2 att))
876 public override RdpPattern AttDeriv (string name, string ns, string value, XmlReader reader)
878 return LValue.AttDeriv (name, ns, value, reader)
880 .Choice (LValue.Interleave (
881 RValue.AttDeriv (name, ns, value, reader)));
884 // startTagCloseDeriv (Interleave p1 p2) =
885 // interleave (startTagCloseDeriv p1) (startTagCloseDeriv p2)
886 public override RdpPattern StartTagCloseDeriv ()
888 return LValue.StartTagCloseDeriv ()
889 .Interleave (RValue.StartTagCloseDeriv ());
893 // FIXME: This is not specified in James Clark's algorithm, so
894 // this may raise unstable behaviour!!
895 // I think this is right but not confident.
897 // ... then I reminded to include it.
898 public override RdpPattern EndTagDeriv ()
900 return LValue.Nullable ? RValue : RdpNotAllowed.Instance;
904 public override RelaxngPatternType PatternType {
905 get { return RelaxngPatternType.Interleave; }
908 internal override void CheckConstraints (bool attribute, bool oneOrMore, bool oneOrMoreGroup, bool oneOrMoreInterleave, bool list, bool dataExcept)
911 throw new RelaxngException ("interleave is not allowed under a list.");
913 throw new RelaxngException ("interleave is not allowed under except of a data.");
916 LValue.CheckConstraints (attribute, oneOrMore, oneOrMoreGroup, oneOrMore, list, dataExcept);
917 RValue.CheckConstraints (attribute, oneOrMore, oneOrMoreGroup, oneOrMore, list, dataExcept);
919 // unique name analysis - 7.3 and part of 7.4
920 CheckNameOverlap (true);
922 // (2) text/text prohibited
923 if (LValue.ContainsText () && RValue.ContainsText ())
924 throw new RelaxngException ("Both branches of the interleave contains a text pattern.");
929 public class RdpGroup : RdpAbstractBinary
931 public RdpGroup (RdpPattern l, RdpPattern r) : base (l, r)
935 public override bool Nullable {
937 if (!nullableComputed) {
939 LValue.Nullable && RValue.Nullable;
940 nullableComputed = true;
946 public override void GetLabels (LabelList elements, LabelList attributes, bool collectNameClass)
948 LValue.GetLabels (elements, attributes, collectNameClass);
950 RValue.GetLabels (elements, attributes, collectNameClass);
952 RValue.GetLabels (null, attributes, collectNameClass);
955 public override RdpPattern TextDeriv (string s, XmlReader reader)
957 RdpPattern p = LValue.TextDeriv (s, reader).Group (RValue);
958 return LValue.Nullable ?
959 p.Choice (RValue.TextDeriv(s, reader)) : p;
962 // startTagOpenDeriv (Group p1 p2) qn =
963 // let x = applyAfter (flip group p2) (startTagOpenDeriv p1 qn)
964 // in if nullable p1 then
965 // choice x (startTagOpenDeriv p2 qn)
968 public override RdpPattern StartTagOpenDeriv (string name, string ns)
970 RdpPattern handled = LValue.StartTagOpenDeriv (name, ns);
971 RdpFlip f = MakeFlip (RdpUtil.GroupFunction, RValue);
972 RdpPattern x = handled.ApplyAfter (new RdpApplyAfterHandler (f.Apply));
974 return x.Choice (RValue.StartTagOpenDeriv (name, ns));
979 // attDeriv cx (Group p1 p2) att =
980 // choice (group (attDeriv cx p1 att) p2)
981 // (group p1 (attDeriv cx p2 att))
982 public override RdpPattern AttDeriv (string name, string ns, string value, XmlReader reader)
984 return LValue.AttDeriv (name, ns, value, reader).Group (RValue)
985 .Choice (LValue.Group (
986 RValue.AttDeriv (name, ns, value, reader)));
989 // startTagCloseDeriv (Group p1 p2) =
990 // group (startTagCloseDeriv p1) (startTagCloseDeriv p2)
991 public override RdpPattern StartTagCloseDeriv ()
993 return LValue.StartTagCloseDeriv ()
994 .Group (RValue.StartTagCloseDeriv ());
997 public override RelaxngPatternType PatternType {
998 get { return RelaxngPatternType.Group; }
1001 internal override void CheckConstraints (bool attribute, bool oneOrMore, bool oneOrMoreGroup, bool oneOrMoreInterleave, bool list, bool dataExcept)
1004 throw new RelaxngException ("interleave is not allowed under except of a data.");
1006 LValue.CheckConstraints (attribute, oneOrMore, oneOrMore, oneOrMoreInterleave, list, dataExcept);
1007 RValue.CheckConstraints (attribute, oneOrMore, oneOrMore, oneOrMoreInterleave, list, dataExcept);
1010 CheckNameOverlap (false);
1014 public abstract class RdpAbstractSingleContent : RdpPattern
1019 internal override RdpPattern ExpandRef (Hashtable defs)
1022 child = child.ExpandRef (defs);
1026 public RdpAbstractSingleContent (RdpPattern p)
1031 public RdpPattern Child {
1032 get { return child; }
1033 set { child = value; }
1036 internal override void MarkReachableDefs ()
1038 child.MarkReachableDefs ();
1041 internal override bool ContainsText()
1043 return child.ContainsText ();
1048 public class RdpOneOrMore : RdpAbstractSingleContent
1050 public RdpOneOrMore (RdpPattern p) : base (p)
1054 public override RelaxngPatternType PatternType {
1055 get { return RelaxngPatternType.OneOrMore; }
1058 public override RdpContentType ContentType {
1060 if (Child.ContentType == RdpContentType.Simple)
1061 throw new RelaxngException ("Invalid content type was found.");
1062 return Child.ContentType;
1066 public override bool Nullable {
1067 get { return Child.Nullable; }
1070 public override void GetLabels (LabelList elements, LabelList attributes, bool collectNameClass)
1072 Child.GetLabels (elements, attributes, collectNameClass);
1075 internal override RdpPattern ReduceEmptyAndNotAllowed (ref bool result, Hashtable visited)
1077 if (visited.Contains (this))
1079 visited.Add (this, this);
1081 if (Child.PatternType == RelaxngPatternType.NotAllowed) {
1083 return RdpNotAllowed.Instance;
1084 } else if (Child.PatternType == RelaxngPatternType.Empty)
1085 return RdpEmpty.Instance;
1087 Child = Child.ReduceEmptyAndNotAllowed (ref result, visited);
1092 public override RdpPattern TextDeriv (string s, XmlReader reader)
1094 return Child.TextDeriv (s, reader).Group (Choice (RdpEmpty.Instance));
1097 // attDeriv cx (OneOrMore p) att =
1098 // group (attDeriv cx p att) (choice (OneOrMore p) Empty)
1099 public override RdpPattern AttDeriv (string name, string ns, string value, XmlReader reader)
1102 return RdpUtil.Group (
1103 RdpUtil.AttDeriv (ctx, children, att),
1104 RdpUtil.Choice (RdpUtil.OneOrMore (children), RdpEmpty.Instance));
1106 return Child.AttDeriv (name, ns, value, reader)
1107 .Group (Choice (RdpEmpty.Instance));
1111 // startTagOpenDeriv (OneOrMore p) qn =
1112 // applyAfter (flip group (choice (OneOrMore p) Empty))
1113 // (startTagOpenDeriv p qn)
1114 public override RdpPattern StartTagOpenDeriv (string name, string ns)
1116 RdpPattern rest = RdpEmpty.Instance.Choice (Child.OneOrMore ());
1117 RdpPattern handled = Child.StartTagOpenDeriv (name, ns);
1118 RdpFlip f = MakeFlip (RdpUtil.GroupFunction, rest);
1119 return handled.ApplyAfter (new RdpApplyAfterHandler (f.Apply));
1122 // startTagCloseDeriv (OneOrMore p) =
1123 // oneOrMore (startTagCloseDeriv p)
1124 public override RdpPattern StartTagCloseDeriv ()
1127 return RdpUtil.OneOrMore (
1128 RdpUtil.StartTagCloseDeriv (children));
1130 return Child.StartTagCloseDeriv ().OneOrMore ();
1134 internal override void CheckConstraints (bool attribute, bool oneOrMore, bool oneOrMoreGroup, bool oneOrMoreInterleave, bool list, bool dataExcept)
1137 throw new RelaxngException ("oneOrMore is not allowed under except of a data.");
1138 this.Child.CheckConstraints (attribute, true, oneOrMoreGroup, oneOrMoreInterleave, list, dataExcept);
1143 public class RdpList : RdpAbstractSingleContent
1145 public RdpList (RdpPattern p) : base (p)
1149 internal override RdpPattern ReduceEmptyAndNotAllowed (ref bool result, Hashtable visited)
1151 if (visited.Contains (this))
1153 visited.Add (this, this);
1155 if (Child.PatternType == RelaxngPatternType.NotAllowed) {
1157 return RdpNotAllowed.Instance;
1159 Child = Child.ReduceEmptyAndNotAllowed (ref result, visited);
1165 // This is not written in James Clark's derivative algorithm
1166 // ( http://www.thaiopensource.com/relaxng/derivative.html ),
1167 // but it looks required.
1168 public override bool Nullable {
1169 get { return this.Child.Nullable; }
1172 // ... but it also causes different error:
1173 // <list><group><data .../><data .../></group></list>
1175 public override bool Nullable {
1176 get { return false; }
1179 public override RelaxngPatternType PatternType {
1180 get { return RelaxngPatternType.List; }
1183 public override RdpContentType ContentType {
1184 get { return RdpContentType.Simple; }
1187 public override void GetLabels (LabelList elements, LabelList attributes, bool collectNameClass)
1189 Child.GetLabels (elements, attributes, collectNameClass);
1192 public override RdpPattern TextDeriv (string s, XmlReader reader)
1194 RdpPattern p = Child.ListDeriv (Util.NormalizeWhitespace (s).Split (RdpUtil.WhitespaceChars), 0, reader);
1196 return RdpEmpty.Instance;
1198 return RdpNotAllowed.Instance;
1201 internal override void CheckConstraints (bool attribute, bool oneOrMore, bool oneOrMoreGroup, bool oneOrMoreInterleave, bool list, bool dataExcept)
1204 throw new RelaxngException ("list is not allowed uner another list.");
1206 throw new RelaxngException ("list is not allowed under except of a data.");
1207 this.Child.CheckConstraints (attribute, oneOrMore, oneOrMoreGroup, oneOrMoreInterleave, true, dataExcept);
1212 public class RdpData : RdpPattern
1214 public RdpData (RdpDatatype dt)
1220 public RdpDatatype Datatype {
1224 // This is not written in James Clark's derivative algorithm
1225 // ( http://www.thaiopensource.com/relaxng/derivative.html ),
1226 // but it looks required.
1227 public override bool Nullable {
1229 if (dt.NamespaceURI.Length == 0)
1235 public override RelaxngPatternType PatternType {
1236 get { return RelaxngPatternType.Data; }
1239 public override RdpContentType ContentType {
1240 get { return RdpContentType.Simple; }
1243 public override void GetLabels (LabelList elements, LabelList attributes, bool collectNameClass)
1248 public override RdpPattern TextDeriv (string s, XmlReader reader)
1250 if (dt.IsAllowed (s, reader))
1251 return RdpEmpty.Instance;
1253 return RdpNotAllowed.Instance;
1256 internal override void MarkReachableDefs ()
1261 internal override void CheckConstraints (bool attribute, bool oneOrMore, bool oneOrMoreGroup, bool oneOrMoreInterleave, bool list, bool dataExcept)
1266 internal override bool ContainsText()
1273 public class RdpDataExcept : RdpData
1275 public RdpDataExcept (RdpDatatype dt, RdpPattern except)
1278 this.except = except;
1282 public RdpPattern Except {
1283 get { return except; }
1284 set { except = value; }
1287 public override RelaxngPatternType PatternType {
1288 get { return RelaxngPatternType.DataExcept; }
1291 public override RdpContentType ContentType {
1293 RdpContentType c = except.ContentType; // conformance required for except pattern.
1294 return RdpContentType.Simple;
1298 internal override RdpPattern ReduceEmptyAndNotAllowed (ref bool result, Hashtable visited)
1300 if (visited.Contains (this))
1302 visited.Add (this, this);
1304 if (except.PatternType == RelaxngPatternType.NotAllowed) {
1306 return new RdpData (this.Datatype);
1308 except = except.ReduceEmptyAndNotAllowed (ref result, visited);
1313 public override RdpPattern TextDeriv (string s, XmlReader reader)
1315 if (Datatype.IsAllowed (s, reader) && !except.TextDeriv (s, reader).Nullable)
1316 return RdpEmpty.Instance;
1318 return RdpNotAllowed.Instance;
1321 internal override void CheckConstraints (bool attribute, bool oneOrMore, bool oneOrMoreGroup, bool oneOrMoreInterleave, bool list, bool dataExcept)
1323 this.except.CheckConstraints (attribute, oneOrMore, oneOrMoreGroup, oneOrMoreInterleave, list, true);
1326 internal override bool ContainsText()
1328 return except.ContainsText ();
1333 public class RdpValue : RdpPattern
1335 public RdpValue (RdpDatatype dt, string value)
1342 public RdpDatatype Datatype {
1347 public string Value {
1348 get { return value; }
1351 // This is not written in James Clark's derivative algorithm
1352 // ( http://www.thaiopensource.com/relaxng/derivative.html ),
1353 // but it looks required.
1354 public override bool Nullable {
1356 if (dt.NamespaceURI.Length == 0 && value.Length == 0)
1362 public override RelaxngPatternType PatternType {
1363 get { return RelaxngPatternType.Value; }
1366 public override RdpContentType ContentType {
1367 get { return RdpContentType.Simple; }
1370 public override void GetLabels (LabelList elements, LabelList attributes, bool collectNameClass)
1375 public override RdpPattern TextDeriv (string s, XmlReader reader)
1377 if (dt.IsTypeEqual (value, s, reader))
1378 return RdpEmpty.Instance;
1380 return RdpNotAllowed.Instance;
1383 internal override void MarkReachableDefs ()
1388 internal override void CheckConstraints (bool attribute, bool oneOrMore, bool oneOrMoreGroup, bool oneOrMoreInterleave, bool list, bool dataExcept)
1390 // nothing to be checked
1393 internal override bool ContainsText()
1400 public class RdpAttribute : RdpPattern
1402 public RdpAttribute (RdpNameClass nameClass, RdpPattern p)
1404 this.nameClass = nameClass;
1408 RdpNameClass nameClass;
1409 public RdpNameClass NameClass {
1410 get { return nameClass; }
1413 RdpPattern children;
1414 public RdpPattern Children {
1415 get { return children; }
1416 set { children = value; }
1419 public override bool Nullable {
1420 get { return false; }
1423 public override RelaxngPatternType PatternType {
1424 get { return RelaxngPatternType.Attribute; }
1427 public override RdpContentType ContentType {
1428 get { return RdpContentType.Empty; }
1431 public override void GetLabels (LabelList elements, LabelList attributes, bool collectNameClass)
1433 if (attributes != null) {
1434 if (collectNameClass)
1435 attributes [NameClass] = NameClass;
1437 AddNameLabel (attributes, NameClass);
1442 internal override RdpPattern ExpandRef (Hashtable defs)
1446 children = children.ExpandRef (defs);
1451 internal override RdpPattern ReduceEmptyAndNotAllowed (ref bool result, Hashtable visited)
1453 if (visited.Contains (this))
1455 visited.Add (this, this);
1457 if (children.PatternType == RelaxngPatternType.NotAllowed) {
1459 return RdpNotAllowed.Instance;
1461 children = children.ReduceEmptyAndNotAllowed (ref result, visited);
1466 // attDeriv cx (Attribute nc p) (AttributeNode qn s) =
1467 // if contains nc qn && valueMatch cx p s then Empty else NotAllowed
1468 public override RdpPattern AttDeriv (string name, string ns, string value, XmlReader reader)
1470 // If value is null, then does not check ValueMatch.
1472 if (RdpUtil.Contains (this.nameClass, att.QName)
1473 && (value == null || RdpUtil.ValueMatch (ctx, this.children, att.Value)))
1474 return RdpEmpty.Instance;
1476 return RdpNotAllowed.Instance;
1478 if (nameClass.Contains (name, ns) &&
1479 (value == null || children.ValueMatch (value, reader)))
1480 return RdpEmpty.Instance;
1482 return RdpNotAllowed.Instance;
1486 // startTagCloseDeriv (Attribute _ _) = NotAllowed
1487 public override RdpPattern StartTagCloseDeriv ()
1489 return RdpNotAllowed.Instance;
1492 internal override void MarkReachableDefs ()
1494 children.MarkReachableDefs ();
1497 internal override void CheckConstraints (bool attribute, bool oneOrMore, bool oneOrMoreGroup, bool oneOrMoreInterleave, bool list, bool dataExcept)
1500 if (attribute || oneOrMoreGroup || oneOrMoreInterleave || list || dataExcept)
1501 throw new RelaxngException ("Not allowed attribute occurence was specified in the pattern.");
1503 // latter part of 7.3
1504 if (!oneOrMore && NameClass.HasInfiniteName)
1505 throw new RelaxngException ("Attributes that has an infinite name class must be repeatable.");
1507 this.Children.CheckConstraints (true, oneOrMore, false, false, false, false);
1510 internal override bool ContainsText()
1512 // This method is to detect text pattern inside interleave child.
1513 // return children.ContainsText ();
1519 public class RdpElement : RdpPattern
1521 public RdpElement (RdpNameClass nameClass, RdpPattern p)
1523 this.nameClass = nameClass;
1527 RdpNameClass nameClass;
1528 public RdpNameClass NameClass {
1529 get { return nameClass; }
1532 RdpPattern children;
1533 public RdpPattern Children {
1534 get { return children; }
1535 set { children = value; }
1538 public override bool Nullable {
1539 get { return false; }
1542 public override RelaxngPatternType PatternType {
1543 get { return RelaxngPatternType.Element; }
1546 bool contentTypeCheckDone;
1547 public override RdpContentType ContentType {
1549 if (!contentTypeCheckDone) {
1550 contentTypeCheckDone = true;
1551 RdpContentType ct = children.ContentType; // conformance required.
1553 return RdpContentType.Complex;
1557 public override void GetLabels (LabelList elements, LabelList attributes, bool collectNameClass)
1559 if (elements != null) {
1560 if (collectNameClass)
1561 elements [NameClass] = NameClass;
1563 AddNameLabel (elements, NameClass);
1569 short expanding; // FIXME: It is totally not required, but there is
1570 // some bugs in simplification and without it it causes infinite loop.
1571 internal override RdpPattern ExpandRef (Hashtable defs)
1575 if (expanding == 100)
1576 throw new RelaxngException (String.Format ("Invalid recursion was found. Name is {0}", nameClass));
1578 children = children.ExpandRef (defs);
1584 internal override RdpPattern ReduceEmptyAndNotAllowed (ref bool result, Hashtable visited)
1586 if (visited.Contains (this))
1588 visited.Add (this, this);
1590 children = children.ReduceEmptyAndNotAllowed (ref result, visited);
1594 public override RdpPattern StartTagOpenDeriv (string name, string ns)
1597 if (RdpUtil.Contains (this.nameClass, qname))
1598 return RdpUtil.After (this.Children, RdpEmpty.Instance);
1600 return RdpNotAllowed.Instance;
1602 return nameClass.Contains (name, ns) ?
1603 children.After (RdpEmpty.Instance) :
1604 RdpNotAllowed.Instance;
1608 internal override void MarkReachableDefs ()
1610 children.MarkReachableDefs ();
1613 bool constraintsChecked;
1614 internal override void CheckConstraints (bool attribute, bool oneOrMore, bool oneOrMoreGroup, bool oneOrMoreInterleave, bool list, bool dataExcept)
1616 if (constraintsChecked)
1618 constraintsChecked = true;
1619 if (attribute || list || dataExcept)
1620 throw new RelaxngException ("Not allowed element occurence was specified in the pattern.");
1621 this.Children.CheckConstraints (false, oneOrMore, oneOrMoreGroup, oneOrMoreInterleave, false, false);
1624 internal override bool ContainsText()
1626 return children.ContainsText ();
1631 public class RdpAfter : RdpAbstractBinary
1633 public RdpAfter (RdpPattern l, RdpPattern r) : base (l, r)
1637 public override bool Nullable {
1638 get { return false; }
1641 public override void GetLabels (LabelList elements, LabelList attributes, bool collectNameClass)
1643 LValue.GetLabels (elements, attributes, collectNameClass);
1646 public override RdpPattern TextDeriv (string s, XmlReader reader)
1648 return LValue.TextDeriv (s, reader).After (RValue);
1651 // startTagOpenDeriv (After p1 p2) qn =
1652 // applyAfter (flip after p2) (startTagOpenDeriv p1 qn)
1653 public override RdpPattern StartTagOpenDeriv (string name, string ns)
1655 RdpPattern handled = LValue.StartTagOpenDeriv (name, ns);
1656 RdpFlip f = MakeFlip (RdpUtil.AfterFunction, RValue);
1657 return handled.ApplyAfter (new RdpApplyAfterHandler (
1661 public override RdpPattern ApplyAfter (RdpApplyAfterHandler handler)
1663 return LValue.After (handler (RValue));
1666 // attDeriv cx (After p1 p2) att =
1667 // after (attDeriv cx p1 att) p2
1668 public override RdpPattern AttDeriv (string name, string ns, string value, XmlReader reader)
1670 return LValue.AttDeriv (name, ns, value, reader).After (RValue);
1673 public override RdpPattern StartTagCloseDeriv ()
1675 return LValue.StartTagCloseDeriv ().After (RValue);
1678 public override RdpPattern EndTagDeriv ()
1680 return LValue.Nullable ? RValue : RdpNotAllowed.Instance;
1683 public override RelaxngPatternType PatternType {
1684 get { return RelaxngPatternType.After; }
1687 internal override void MarkReachableDefs ()
1689 throw new InvalidOperationException ();
1692 internal override void CheckConstraints (bool attribute, bool oneOrMore, bool oneOrMoreGroup, bool oneOrMoreInterleave, bool list, bool dataExcept)
1694 throw new InvalidOperationException ();
1697 internal override bool ContainsText ()
1699 throw new InvalidOperationException ();