2 // Mono.Xml.Schema.XsdParticleValidationState.cs
5 // Atsushi Enomoto (ginga@kit.hi-ho.ne.jp)
7 // (C)2003 Atsushi Enomoto
10 using System.Collections;
12 using System.Xml.Schema;
15 namespace Mono.Xml.Schema
17 public enum XsdParticleEvaluationResult
19 Matched = 1, // Matched one of its components.
20 Passed = 2, // Did not match, but it successfully passed the whole components.
21 InvalidIncomplete = 3, // It had incomplete validation state, and in fact it failed to pass.
22 Mismatched = 4 // Dis not match,
25 public class XsdValidationStateManager
28 XmlSchemaElement currentElement;
29 XmlSchemaContentProcessing processContents;
31 public XsdValidationStateManager ()
33 table = new Hashtable ();
34 processContents = XmlSchemaContentProcessing.Strict; // not Lax
37 public XmlSchemaElement CurrentElement {
38 get { return currentElement; }
39 set { currentElement = value; }
42 internal void SetCurrentElement (XmlSchemaElement elt)
44 this.currentElement = elt;
47 public XmlSchemaContentProcessing ProcessContents {
48 get { return processContents; }
51 internal void SetProcessContents (XmlSchemaContentProcessing value)
53 this.processContents = value;
56 public XsdValidationState Get (XmlSchemaParticle xsobj)
58 XsdValidationState got = table [xsobj] as XsdValidationState;
64 public XsdValidationState Create (XmlSchemaObject xsobj)
66 string typeName = xsobj.GetType ().Name;
68 case "XmlSchemaElement":
69 return AddElement ((XmlSchemaElement) xsobj);
70 case "XmlSchemaGroupRef":
71 return AddGroup ((XmlSchemaGroupRef) xsobj);
72 case "XmlSchemaSequence":
73 return AddSequence ((XmlSchemaSequence) xsobj);
74 case "XmlSchemaChoice":
75 return AddChoice ((XmlSchemaChoice) xsobj);
77 return AddAll ((XmlSchemaAll) xsobj);
79 return AddAny ((XmlSchemaAny) xsobj);
80 case "EmptyParticle": // Microsoft.NET
81 case "XmlSchemaParticleEmpty": // Mono
84 throw new InvalidOperationException (); // Should not occur.
88 internal XsdValidationState MakeSequence (XsdValidationState head, XsdValidationState rest)
90 if (head is XsdEmptyValidationState)
93 return new XsdAppendedValidationState (this, head, rest);
96 private XsdElementValidationState AddElement (XmlSchemaElement element)
98 XsdElementValidationState got = new XsdElementValidationState (element, this);
99 // table [element] = got;
103 private XsdGroupValidationState AddGroup (XmlSchemaGroupRef groupRef)
105 XsdGroupValidationState got = new XsdGroupValidationState (groupRef, this);
106 // table [groupRef] = got;
110 private XsdSequenceValidationState AddSequence (XmlSchemaSequence sequence)
112 XsdSequenceValidationState got = new XsdSequenceValidationState (sequence, this);
113 // table [sequence] = got;
117 private XsdChoiceValidationState AddChoice (XmlSchemaChoice choice)
119 XsdChoiceValidationState got = new XsdChoiceValidationState (choice, this);
120 // table [choice] = got;
124 private XsdAllValidationState AddAll (XmlSchemaAll all)
126 XsdAllValidationState got = new XsdAllValidationState (all, this);
127 // table [all] = got;
131 private XsdAnyValidationState AddAny (XmlSchemaAny any)
133 XsdAnyValidationState got = new XsdAnyValidationState (any, this);
134 // table [any] = got;
138 private XsdEmptyValidationState AddEmpty ()
140 return new XsdEmptyValidationState (this);
144 public abstract class XsdValidationState
148 static XsdInvalidValidationState invalid;
150 static XsdValidationState ()
152 invalid = new XsdInvalidValidationState (null);
155 public static XsdInvalidValidationState Invalid {
156 get { return invalid; }
163 XsdValidationStateManager manager;
165 public XsdValidationState (XsdValidationStateManager manager)
167 this.manager = manager;
170 // Normally checks MaxOccurs boundary
171 public abstract XsdValidationState EvaluateStartElement (string localName, string ns);
173 // Normally checks MinOccurs boundary
174 public abstract bool EvaluateEndElement ();
176 internal abstract bool EvaluateIsEmptiable ();
178 public XsdValidationStateManager Manager {
179 get { return manager; }
182 public string Message {
183 get { return message; }
186 public string MessageInternal {
187 get { return message; }
188 set { message = value; }
192 get { return occured; }
195 internal int OccuredInternal {
196 get { return occured; }
197 set { occured = value; }
201 public class XsdElementValidationState : XsdValidationState
203 public XsdElementValidationState (XmlSchemaElement element, XsdValidationStateManager manager)
206 this.element = element;
207 name = element.QualifiedName.Name;
208 ns = element.QualifiedName.Namespace;
212 XmlSchemaElement element;
218 public override XsdValidationState EvaluateStartElement (string name, string ns)
220 if (this.name == name && this.ns == ns && !element.IsAbstract) {
221 return this.CheckOccurence (element);
223 foreach (XmlSchemaElement subst in element.SubstitutingElements) {
224 if (subst.QualifiedName.Name == name &&
225 subst.QualifiedName.Namespace == ns) {
226 return this.CheckOccurence (subst);
229 return XsdValidationState.Invalid;
233 private XsdValidationState CheckOccurence (XmlSchemaElement maybeSubstituted)
236 Manager.SetCurrentElement (maybeSubstituted);
237 if (Occured > element.ValidatedMaxOccurs) {
238 MessageInternal = "Element occurence excess.";
239 return XsdValidationState.Invalid;
240 } else if (Occured == element.ValidatedMaxOccurs) {
241 return Manager.Create (XmlSchemaParticle.Empty);
247 public override bool EvaluateEndElement ()
249 return EvaluateIsEmptiable ();
252 internal override bool EvaluateIsEmptiable ()
254 return (element.ValidatedMinOccurs <= Occured &&
255 element.ValidatedMaxOccurs >= Occured);
259 public class XsdGroupValidationState : XsdValidationState
261 public XsdGroupValidationState (XmlSchemaGroupRef groupRef, XsdValidationStateManager manager)
264 this.groupRef = groupRef;
267 XmlSchemaGroupRef groupRef;
271 public override XsdValidationState EvaluateStartElement (string name, string ns)
273 XsdValidationState xa = Manager.Create (groupRef.Particle);
274 XsdValidationState result = xa.EvaluateStartElement (name, ns);
275 if (result == XsdValidationState.Invalid)
279 if (OccuredInternal > groupRef.MaxOccurs)
280 return XsdValidationState.Invalid;
281 return Manager.MakeSequence (result, this);
284 public override bool EvaluateEndElement ()
286 if (groupRef.ValidatedMinOccurs > Occured + 1)
288 else if (groupRef.ValidatedMinOccurs <= Occured)
290 return Manager.Create (groupRef.Particle).EvaluateIsEmptiable ();
293 internal override bool EvaluateIsEmptiable ()
\r
295 return (groupRef.ValidatedMinOccurs <= Occured);
\r
299 public class XsdSequenceValidationState : XsdValidationState
301 XmlSchemaSequence seq;
303 XsdValidationState currentAutomata;
308 public XsdSequenceValidationState (XmlSchemaSequence sequence, XsdValidationStateManager manager)
309 : this (sequence, manager, sequence.ValidatedMinOccurs, sequence.ValidatedMaxOccurs, -1)
313 public XsdSequenceValidationState (XmlSchemaSequence sequence, XsdValidationStateManager manager,
314 decimal minOccurs, decimal maxOccurs, int current)
318 this.minOccurs = minOccurs;
319 this.maxOccurs = maxOccurs;
320 this.current = current;
323 public override XsdValidationState EvaluateStartElement (string name, string ns)
325 if (seq.CompiledItems.Count == 0)
326 return XsdValidationState.Invalid;
328 int idx = current < 0 ? 0 : current;
329 XsdValidationState xa = currentAutomata;
330 // If it is true and when matching particle was found, then
331 // it will increment occurence.
332 bool increment = false;
335 // if (current < 0 || current == seq.CompiledItems.Count) {
336 // idx = current = 0;
339 if (xa == null) { // This code runs in case of a newiteration.
340 xa = Manager.Create (seq.CompiledItems [idx] as XmlSchemaParticle);
343 if (xa is XsdEmptyValidationState &&
344 seq.CompiledItems.Count == idx + 1 &&
345 Occured == maxOccurs) {
346 return XsdValidationState.Invalid;
348 XsdValidationState result = xa.EvaluateStartElement (name, ns);
349 if (result == XsdValidationState.Invalid) {
350 if (!xa.EvaluateIsEmptiable ()) {
352 return XsdValidationState.Invalid;
356 currentAutomata = result;
359 if (Occured > maxOccurs)
360 return XsdValidationState.Invalid;
363 // return Manager.MakeSequence (result, this);
365 // skip in other cases.
369 if (idx > current && increment && current >= 0) {
370 return XsdValidationState.Invalid;
372 if (seq.CompiledItems.Count > idx) {
373 xa = Manager.Create (seq.CompiledItems [idx] as XmlSchemaParticle);
375 else if (current < 0) { // started from top
376 return XsdValidationState.Invalid;
378 else { // started from middle
383 return XsdValidationState.Invalid;
386 public override bool EvaluateEndElement ()
388 if (minOccurs > Occured + 1)
390 if (seq.CompiledItems.Count == 0)
392 if (currentAutomata == null && minOccurs <= Occured)
395 int idx = current < 0 ? 0 : current;
396 XsdValidationState xa = currentAutomata;
398 xa = Manager.Create (seq.CompiledItems [idx] as XmlSchemaParticle);
400 if (!xa.EvaluateEndElement ())
401 if (!xa.EvaluateIsEmptiable ())
402 return false; // cannot omit following items.
404 if (seq.CompiledItems.Count > idx)
405 xa = Manager.Create (seq.CompiledItems [idx] as XmlSchemaParticle);
412 return minOccurs <= Occured && maxOccurs >= Occured;
415 internal override bool EvaluateIsEmptiable ()
\r
417 if (minOccurs > Occured + 1)
\r
419 if (minOccurs == 0 && currentAutomata == null)
\r
424 if (seq.CompiledItems.Count == 0)
\r
427 int idx = current < 0 ? 0 : current;
428 XsdValidationState xa = currentAutomata;
\r
430 xa = Manager.Create (seq.CompiledItems [idx] as XmlSchemaParticle);
432 if (!xa.EvaluateIsEmptiable ())
435 if (seq.CompiledItems.Count > idx)
436 xa = Manager.Create (seq.CompiledItems [idx] as XmlSchemaParticle);
446 public class XsdChoiceValidationState : XsdValidationState
448 XmlSchemaChoice choice;
450 bool emptiableComputed;
452 public XsdChoiceValidationState (XmlSchemaChoice choice, XsdValidationStateManager manager)
455 this.choice = choice;
458 public override XsdValidationState EvaluateStartElement (string localName, string ns)
460 emptiableComputed = false;
462 foreach (XmlSchemaParticle xsobj in choice.CompiledItems) {
463 XsdValidationState xa = Manager.Create (xsobj);
464 XsdValidationState result = xa.EvaluateStartElement (localName, ns);
465 if (result != XsdValidationState.Invalid) {
467 if (Occured > choice.ValidatedMaxOccurs)
468 return XsdValidationState.Invalid;
469 else if (Occured == choice.ValidatedMaxOccurs)
472 return Manager.MakeSequence (result, this);
475 emptiable = choice.ValidatedMinOccurs <= Occured;
476 emptiableComputed = true;
477 return XsdValidationState.Invalid;
480 public override bool EvaluateEndElement ()
482 emptiableComputed = false;
484 if (choice.ValidatedMinOccurs > Occured + 1)
487 else if (choice.ValidatedMinOccurs <= Occured)
490 foreach (XmlSchemaParticle p in choice.CompiledItems)
491 if (Manager.Create (p).EvaluateIsEmptiable ())
496 internal override bool EvaluateIsEmptiable ()
\r
498 if (emptiableComputed)
501 if (choice.ValidatedMaxOccurs < Occured)
\r
503 else if (choice.ValidatedMinOccurs > Occured + 1)
\r
506 for (int i = Occured; i < choice.ValidatedMinOccurs; i++) {
\r
508 foreach (XmlSchemaParticle p in choice.CompiledItems) {
\r
509 if (Manager.Create (p).EvaluateIsEmptiable ()) {
521 public class XsdAllValidationState : XsdValidationState
524 ArrayList consumed = new ArrayList ();
526 public XsdAllValidationState (XmlSchemaAll all, XsdValidationStateManager manager)
532 public override XsdValidationState EvaluateStartElement (string localName, string ns)
534 if (all.CompiledItems.Count == 0)
535 return XsdValidationState.Invalid;
537 // We don't have to keep element validation state, since
538 // it must occur only 0 or 1.
539 foreach (XmlSchemaElement xsElem in all.CompiledItems) {
540 if (xsElem.QualifiedName.Name == localName &&
541 xsElem.QualifiedName.Namespace == ns) {
542 if (consumed.Contains (xsElem))
543 return XsdValidationState.Invalid;
544 consumed.Add (xsElem);
545 Manager.SetCurrentElement (xsElem);
546 OccuredInternal = 1; // xs:all also occurs 0 or 1 always.
550 return XsdValidationState.Invalid;
553 public override bool EvaluateEndElement ()
555 if (all.Emptiable || all.ValidatedMinOccurs == 0)
557 if (all.ValidatedMinOccurs > 0 && consumed.Count == 0)
559 if (all.CompiledItems.Count == consumed.Count)
561 foreach (XmlSchemaElement el in all.CompiledItems)
562 if (el.MinOccurs > 0 && !consumed.Contains (el))
567 internal override bool EvaluateIsEmptiable ()
\r
569 if (all.Emptiable || all.ValidatedMinOccurs == 0)
571 foreach (XmlSchemaElement el in all.CompiledItems)
572 if (el.MinOccurs > 0 && !consumed.Contains (el))
578 public class XsdAnyValidationState : XsdValidationState
582 public XsdAnyValidationState (XmlSchemaAny any, XsdValidationStateManager manager)
589 public override XsdValidationState EvaluateStartElement (string name, string ns)
591 if (!MatchesNamespace (ns))
592 return XsdValidationState.Invalid;
595 Manager.SetProcessContents (any.ProcessContents);
596 if (Occured > any.ValidatedMaxOccurs)
597 return XsdValidationState.Invalid;
598 else if (Occured == any.ValidatedMaxOccurs)
599 return Manager.Create (XmlSchemaParticle.Empty);
604 private bool MatchesNamespace (string ns)
608 if (any.HasValueLocal && ns == String.Empty)
610 if (any.HasValueOther && (any.TargetNamespace == "" || any.TargetNamespace != ns))
612 if (any.HasValueTargetNamespace && any.TargetNamespace == ns)
614 foreach (string iter in any.ResolvedNamespaces)
620 public override bool EvaluateEndElement ()
622 return EvaluateIsEmptiable ();
625 internal override bool EvaluateIsEmptiable ()
\r
627 return any.ValidatedMinOccurs <= Occured &&
628 any.ValidatedMaxOccurs >= Occured;
632 public class XsdAppendedValidationState : XsdValidationState
634 public XsdAppendedValidationState (XsdValidationStateManager manager,
635 XsdValidationState head, XsdValidationState rest)
642 XsdValidationState head;
643 XsdValidationState rest;
646 public override XsdValidationState EvaluateStartElement (string name, string ns)
648 XsdValidationState afterHead = head.EvaluateStartElement (name, ns);
649 if (afterHead != XsdValidationState.Invalid) {
651 return afterHead is XsdEmptyValidationState ? rest : this;
652 } else if (!head.EvaluateIsEmptiable ()) {
653 return XsdValidationState.Invalid;
656 return rest.EvaluateStartElement (name, ns);
659 public override bool EvaluateEndElement ()
661 if (head.EvaluateEndElement ())
663 return rest.EvaluateIsEmptiable ();
664 if (!head.EvaluateIsEmptiable ())
666 return rest.EvaluateEndElement ();
669 internal override bool EvaluateIsEmptiable ()
\r
671 if (head.EvaluateIsEmptiable ())
\r
672 return rest.EvaluateIsEmptiable ();
\r
678 public class XsdEmptyValidationState : XsdValidationState
680 public XsdEmptyValidationState (XsdValidationStateManager manager)
686 public override XsdValidationState EvaluateStartElement (string name, string ns)
688 return XsdValidationState.Invalid;
691 public override bool EvaluateEndElement ()
696 internal override bool EvaluateIsEmptiable ()
\r
703 public class XsdInvalidValidationState : XsdValidationState
705 internal XsdInvalidValidationState (XsdValidationStateManager manager)
711 public override XsdValidationState EvaluateStartElement (string name, string ns)
716 public override bool EvaluateEndElement ()
721 internal override bool EvaluateIsEmptiable ()
\r