2 // Mono.Xml.Schema.XsdValidatingReader.cs
5 // Atsushi Enomoto (ginga@kit.hi-ho.ne.jp)
7 // (C)2003 Atsushi Enomoto
11 // This class doesn't support set_XmlResolver, since it isn't common to XmlReader interface.
12 // Try to set that of xml reader which is used to construct this object.
16 // Permission is hereby granted, free of charge, to any person obtaining
17 // a copy of this software and associated documentation files (the
18 // "Software"), to deal in the Software without restriction, including
19 // without limitation the rights to use, copy, modify, merge, publish,
20 // distribute, sublicense, and/or sell copies of the Software, and to
21 // permit persons to whom the Software is furnished to do so, subject to
22 // the following conditions:
24 // The above copyright notice and this permission notice shall be
25 // included in all copies or substantial portions of the Software.
27 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
28 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
29 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
30 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
31 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
32 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
33 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
36 using System
.Collections
;
37 using System
.Collections
.Specialized
;
40 using System
.Xml
.Schema
;
43 namespace Mono
.Xml
.Schema
45 internal class XsdValidatingReader
: XmlReader
, IXmlLineInfo
, IHasXmlSchemaInfo
, IHasXmlParserContext
, IXmlNamespaceResolver
47 static char [] wsChars
= new char [] {' ', '\t', '\n', '\r'}
;
50 XmlValidatingReader xvReader
;
52 IHasXmlSchemaInfo sourceReaderSchemaInfo
;
53 IXmlLineInfo readerLineInfo
;
54 bool laxElementValidation
= true;
55 bool reportNoValidationError
;
56 XmlSchemaSet schemas
= new XmlSchemaSet ();
57 bool namespaces
= true;
59 Hashtable idList
= new Hashtable ();
60 ArrayList missingIDReferences
;
63 ArrayList keyTables
= new ArrayList ();
64 ArrayList currentKeyFieldConsumers
;
66 XsdValidationStateManager stateManager
= new XsdValidationStateManager ();
67 XsdValidationContext context
= new XsdValidationContext ();
68 XsdValidationState childParticleState
;
71 StringBuilder storedCharacters
= new StringBuilder ();
72 bool shouldValidateCharacters
;
73 int skipValidationDepth
= -1;
75 XmlSchemaAttribute
[] defaultAttributes
= new XmlSchemaAttribute
[0];
76 int currentDefaultAttribute
= -1;
77 XmlQualifiedName currentQName
;
79 ArrayList elementQNameStack
= new ArrayList ();
83 int nonDefaultAttributeCount
;
84 bool defaultAttributeConsumed
;
86 // Validation engine cached object
87 ArrayList defaultAttributesCache
;
88 ArrayList tmpKeyrefPool
;
91 public XsdValidatingReader (XmlReader reader
)
96 public XsdValidatingReader (XmlReader reader
, XmlReader validatingReader
)
99 xvReader
= validatingReader
as XmlValidatingReader
;
100 if (xvReader
!= null) {
101 if (xvReader
.ValidationType
== ValidationType
.None
)
102 reportNoValidationError
= true;
104 readerLineInfo
= reader
as IXmlLineInfo
;
105 sourceReaderSchemaInfo
= reader
as IHasXmlSchemaInfo
;
108 // Provate Properties
109 private XmlQualifiedName CurrentQName
{
111 if (currentQName
== null)
112 currentQName
= new XmlQualifiedName (LocalName
, NamespaceURI
);
117 internal ArrayList CurrentKeyFieldConsumers
{
119 if (currentKeyFieldConsumers
== null)
120 currentKeyFieldConsumers
= new ArrayList ();
121 return currentKeyFieldConsumers
;
125 private ArrayList DefaultAttributesCache
{
127 if (defaultAttributesCache
== null)
128 defaultAttributesCache
= new ArrayList ();
129 return defaultAttributesCache
;
133 private ArrayList MissingIDReferences
{
135 if (missingIDReferences
== null)
136 missingIDReferences
= new ArrayList ();
137 return missingIDReferences
;
141 // Public Non-overrides
143 public int XsiNilDepth
{
144 get { return xsiNilDepth; }
147 public bool Namespaces
{
148 get { return namespaces; }
149 set { namespaces = value; }
152 public XmlReader Reader
{
153 get { return reader; }
156 // This is required to resolve xsi:schemaLocation
157 public XmlResolver XmlResolver
{
163 // This should be changed before the first Read() call.
164 public XmlSchemaSet Schemas
{
165 get { return schemas; }
167 if (ReadState
!= ReadState
.Initial
)
168 throw new InvalidOperationException ("Schemas must be set before the first call to Read().");
173 public object SchemaType
{
175 if (ReadState
!= ReadState
.Interactive
)
179 case XmlNodeType
.Element
:
180 if (context
.ActualType
!= null)
181 return context
.ActualType
;
182 else if (context
.Element
!= null)
183 return context
.Element
.ElementType
;
185 return SourceReaderSchemaType
;
186 case XmlNodeType
.Attribute
:
187 XmlSchemaComplexType ct
= context
.ActualType
as XmlSchemaComplexType
;
189 XmlSchemaAttribute attdef
= ct
.AttributeUses
[CurrentQName
] as XmlSchemaAttribute
;
191 return attdef
.AttributeType
;
193 return SourceReaderSchemaType
;
195 return SourceReaderSchemaType
;
200 private object SourceReaderSchemaType
{
201 get { return this.sourceReaderSchemaInfo != null ? sourceReaderSchemaInfo.SchemaType : null; }
204 // This property is never used in Mono.
205 public ValidationType ValidationType
{
207 if (reportNoValidationError
)
208 return ValidationType
.None
;
210 return ValidationType
.Schema
;
214 IDictionary IXmlNamespaceResolver
.GetNamespacesInScope (XmlNamespaceScope scope
)
216 IXmlNamespaceResolver resolver
= reader
as IXmlNamespaceResolver
;
217 if (resolver
== null)
218 throw new NotSupportedException ("The input XmlReader does not implement IXmlNamespaceResolver and thus this validating reader cannot collect in-scope namespaces.");
219 return resolver
.GetNamespacesInScope (scope
);
222 string IXmlNamespaceResolver
.LookupPrefix (string ns
)
224 return ((IXmlNamespaceResolver
) this).LookupPrefix (ns
, false);
227 string IXmlNamespaceResolver
.LookupPrefix (string ns
, bool atomizedNames
)
229 IXmlNamespaceResolver resolver
= reader
as IXmlNamespaceResolver
;
230 if (resolver
== null)
231 throw new NotSupportedException ("The input XmlReader does not implement IXmlNamespaceResolver and thus this validating reader cannot execute namespace prefix lookup.");
232 return resolver
.LookupPrefix (ns
, atomizedNames
);
235 // It is used only for independent XmlReader use, not for XmlValidatingReader.
237 public override object ReadTypedValue ()
239 public object ReadTypedValue ()
242 XmlSchemaDatatype dt
= SchemaType
as XmlSchemaDatatype
;
243 XmlSchemaSimpleType st
= SchemaType
as XmlSchemaSimpleType
;
250 case XmlNodeType
.Element
:
254 storedCharacters
.Length
= 0;
259 case XmlNodeType
.SignificantWhitespace
:
260 case XmlNodeType
.Text
:
261 case XmlNodeType
.CDATA
:
262 storedCharacters
.Append (Value
);
264 case XmlNodeType
.Comment
:
270 } while (loop
&& !EOF
&& ReadState
== ReadState
.Interactive
);
271 return dt
.ParseValue (storedCharacters
.ToString (), NameTable
, ParserContext
.NamespaceManager
);
272 case XmlNodeType
.Attribute
:
273 return dt
.ParseValue (Value
, NameTable
, ParserContext
.NamespaceManager
);
278 public ValidationEventHandler ValidationEventHandler
;
280 // Public Overrided Properties
282 public override int AttributeCount
{
284 return nonDefaultAttributeCount
+ defaultAttributes
.Length
;
288 public override string BaseURI
{
289 get { return reader.BaseURI; }
292 // If this class is used to implement XmlValidatingReader,
293 // it should be left to DTDValidatingReader. In other cases,
294 // it depends on the reader's ability.
295 public override bool CanResolveEntity
{
296 get { return reader.CanResolveEntity; }
299 public override int Depth
{
301 if (currentDefaultAttribute
< 0)
303 if (this.defaultAttributeConsumed
)
304 return reader
.Depth
+ 2;
305 return reader
.Depth
+ 1;
309 public override bool EOF
{
310 get { return reader.EOF; }
313 public override bool HasValue
{
315 if (currentDefaultAttribute
< 0)
316 return reader
.HasValue
;
321 public override bool IsDefault
{
323 if (currentDefaultAttribute
< 0)
324 return reader
.IsDefault
;
329 public override bool IsEmptyElement
{
331 if (currentDefaultAttribute
< 0)
332 return reader
.IsEmptyElement
;
337 public override string this [int i
] {
338 get { return GetAttribute (i); }
341 public override string this [string name
] {
342 get { return GetAttribute (name); }
345 public override string this [string localName
, string ns
] {
346 get { return GetAttribute (localName, ns); }
349 int IXmlLineInfo
.LineNumber
{
350 get { return readerLineInfo != null ? readerLineInfo.LineNumber : 0; }
353 int IXmlLineInfo
.LinePosition
{
354 get { return readerLineInfo != null ? readerLineInfo.LinePosition : 0; }
357 public override string LocalName
{
359 if (currentDefaultAttribute
< 0)
360 return reader
.LocalName
;
361 if (defaultAttributeConsumed
)
363 return defaultAttributes
[currentDefaultAttribute
].QualifiedName
.Name
;
367 public override string Name
{
369 if (currentDefaultAttribute
< 0)
371 if (defaultAttributeConsumed
)
374 XmlQualifiedName qname
= defaultAttributes
[currentDefaultAttribute
].QualifiedName
;
375 string prefix
= Prefix
;
376 if (prefix
== String
.Empty
)
379 return String
.Concat (prefix
, ":", qname
.Name
);
383 public override string NamespaceURI
{
385 if (currentDefaultAttribute
< 0)
386 return reader
.NamespaceURI
;
387 if (defaultAttributeConsumed
)
389 return defaultAttributes
[currentDefaultAttribute
].QualifiedName
.Namespace
;
393 public override XmlNameTable NameTable
{
394 get { return reader.NameTable; }
397 public override XmlNodeType NodeType
{
399 if (currentDefaultAttribute
< 0)
400 return reader
.NodeType
;
401 if (defaultAttributeConsumed
)
402 return XmlNodeType
.Text
;
403 return XmlNodeType
.Attribute
;
407 public XmlParserContext ParserContext
{
408 get { return XmlSchemaUtil.GetParserContext (reader); }
411 public override string Prefix
{
413 if (currentDefaultAttribute
< 0)
414 return reader
.Prefix
;
415 if (defaultAttributeConsumed
)
417 XmlQualifiedName qname
= defaultAttributes
[currentDefaultAttribute
].QualifiedName
;
418 string prefix
= this.ParserContext
.NamespaceManager
.LookupPrefix (qname
.Namespace
, false);
426 public override char QuoteChar
{
427 get { return reader.QuoteChar; }
430 public override ReadState ReadState
{
431 get { return reader.ReadState; }
434 public override string Value
{
436 if (currentDefaultAttribute
< 0)
438 string value = defaultAttributes
[currentDefaultAttribute
].ValidatedDefaultValue
;
440 value = defaultAttributes
[currentDefaultAttribute
].ValidatedFixedValue
;
445 XmlQualifiedName qnameXmlLang
= new XmlQualifiedName ("lang", XmlNamespaceManager
.XmlnsXml
);
447 public override string XmlLang
{
449 string xmlLang
= reader
.XmlLang
;
452 int idx
= this.FindDefaultAttribute ("lang", XmlNamespaceManager
.XmlnsXml
);
455 xmlLang
= defaultAttributes
[idx
].ValidatedDefaultValue
;
457 xmlLang
= defaultAttributes
[idx
].ValidatedFixedValue
;
462 public override XmlSpace XmlSpace
{
464 XmlSpace space
= reader
.XmlSpace
;
465 if (space
!= XmlSpace
.None
)
467 int idx
= this.FindDefaultAttribute ("space", XmlNamespaceManager
.XmlnsXml
);
469 return XmlSpace
.None
;
470 string spaceSpec
= defaultAttributes
[idx
].ValidatedDefaultValue
;
471 if (spaceSpec
== null)
472 spaceSpec
= defaultAttributes
[idx
].ValidatedFixedValue
;
473 return (XmlSpace
) Enum
.Parse (typeof (XmlSpace
), spaceSpec
, false);
479 private XmlQualifiedName
QualifyName (string name
)
481 return XmlQualifiedName
.Parse (name
, this);
484 private void HandleError (string error
)
486 HandleError (error
, null);
489 private void HandleError (string error
, Exception innerException
)
491 HandleError (error
, innerException
, false);
494 private void HandleError (string error
, Exception innerException
, bool isWarning
)
496 if (reportNoValidationError
) // extra quick check
499 XmlSchemaException schemaException
= new XmlSchemaException (error
,
500 this, this.BaseURI
, null, innerException
);
501 HandleError (schemaException
, isWarning
);
504 private void HandleError (XmlSchemaException schemaException
)
506 HandleError (schemaException
, false);
509 private void HandleError (XmlSchemaException schemaException
, bool isWarning
)
511 if (reportNoValidationError
)
514 ValidationEventArgs e
= new ValidationEventArgs (schemaException
,
515 schemaException
.Message
, isWarning
? XmlSeverityType
.Warning
: XmlSeverityType
.Error
);
517 if (this.ValidationEventHandler
!= null)
518 this.ValidationEventHandler (this, e
);
519 else if (xvReader
!= null)
520 xvReader
.OnValidationEvent (this, e
);
521 else if (e
.Severity
== XmlSeverityType
.Error
)
523 this.xvReader
.OnValidationEvent (this, e
);
529 private XmlSchemaElement
FindElement (string name
, string ns
)
531 return (XmlSchemaElement
) schemas
.GlobalElements
[new XmlQualifiedName (name
, ns
)];
534 private XmlSchemaType
FindType (XmlQualifiedName qname
)
536 return (XmlSchemaType
) schemas
.GlobalTypes
[qname
];
539 private void ValidateStartElementParticle ()
541 stateManager
.CurrentElement
= null;
542 context
.ParticleState
= context
.ParticleState
.EvaluateStartElement (reader
.LocalName
, reader
.NamespaceURI
);
543 if (context
.ParticleState
== XsdValidationState
.Invalid
)
544 HandleError ("Invalid start element: " + reader
.NamespaceURI
+ ":" + reader
.LocalName
);
546 context
.Element
= stateManager
.CurrentElement
;
547 if (context
.Element
!= null)
548 context
.SchemaType
= context
.Element
.ElementType
;
551 private void ValidateEndElementParticle ()
553 if (childParticleState
!= null) {
554 if (!childParticleState
.EvaluateEndElement ()) {
555 HandleError ("Invalid end element: " + reader
.Name
);
558 context
.PopScope (reader
.Depth
);
561 // Utility for missing validation completion related to child items.
562 private void ValidateCharacters ()
564 if (xsiNilDepth
>= 0 && xsiNilDepth
< reader
.Depth
)
565 HandleError ("Element item appeared, while current element context is nil.");
567 storedCharacters
.Append (reader
.Value
);
570 // Utility for missing validation completion related to child items.
571 private void ValidateEndCharacters ()
573 if (context
.ActualType
== null)
576 string value = storedCharacters
.ToString ();
578 if (storedCharacters
.Length
== 0) {
579 // 3.3.4 Element Locally Valid (Element) 5.1.2
580 if (context
.Element
!= null) {
581 if (context
.Element
.ValidatedDefaultValue
!= null)
582 value = context
.Element
.ValidatedDefaultValue
;
586 XmlSchemaDatatype dt
= context
.ActualType
as XmlSchemaDatatype
;
587 XmlSchemaSimpleType st
= context
.ActualType
as XmlSchemaSimpleType
;
592 XmlSchemaComplexType ct
= context
.ActualType
as XmlSchemaComplexType
;
594 switch (ct
.ContentType
) {
595 case XmlSchemaContentType
.ElementOnly
:
596 case XmlSchemaContentType
.Empty
:
597 if (storedCharacters
.Length
> 0)
598 HandleError ("Character content not allowed.");
604 // 3.3.4 Element Locally Valid (Element) :: 5.2.2.2. Fixed value constraints
605 if (context
.Element
!= null && context
.Element
.ValidatedFixedValue
!= null)
606 if (value != context
.Element
.ValidatedFixedValue
)
607 HandleError ("Fixed value constraint was not satisfied.");
608 AssessStringValid (st
, dt
, value);
611 // Identity field value
612 if (currentKeyFieldConsumers
!= null) {
613 while (this.currentKeyFieldConsumers
.Count
> 0) {
614 XsdKeyEntryField field
= this.currentKeyFieldConsumers
[0] as XsdKeyEntryField
;
615 if (field
.Identity
!= null)
616 HandleError ("Two or more identical field was found. Former value is '" + field
.Identity
+ "' .");
617 object identity
= null; // This means empty value
620 identity
= dt
.ParseValue (value, NameTable
, ParserContext
.NamespaceManager
);
621 } catch (Exception ex
) { // FIXME: (wishlist) This is bad manner ;-(
622 HandleError ("Identity value is invalid against its data type " + dt
.TokenizedType
, ex
);
625 if (identity
== null)
628 if (!field
.SetIdentityField (identity
, reader
.Depth
== xsiNilDepth
, dt
as XsdAnySimpleType
, this))
629 HandleError ("Two or more identical key value was found: '" + value + "' .");
630 this.currentKeyFieldConsumers
.RemoveAt (0);
634 shouldValidateCharacters
= false;
637 // 3.14.4 String Valid
638 private void AssessStringValid (XmlSchemaSimpleType st
,
639 XmlSchemaDatatype dt
, string value)
641 XmlSchemaDatatype validatedDatatype
= dt
;
643 string normalized
= validatedDatatype
.Normalize (value);
645 XmlSchemaDatatype itemDatatype
;
646 XmlSchemaSimpleType itemSimpleType
;
647 switch (st
.DerivedBy
) {
648 case XmlSchemaDerivationMethod
.List
:
649 XmlSchemaSimpleTypeList listContent
= st
.Content
as XmlSchemaSimpleTypeList
;
650 values
= normalized
.Split (wsChars
);
651 itemDatatype
= listContent
.ValidatedListItemType
as XmlSchemaDatatype
;
652 itemSimpleType
= listContent
.ValidatedListItemType
as XmlSchemaSimpleType
;
653 for (int vi
= 0; vi
< values
.Length
; vi
++) {
654 string each
= values
[vi
];
655 if (each
== String
.Empty
)
657 // validate against ValidatedItemType
658 if (itemDatatype
!= null) {
660 itemDatatype
.ParseValue (each
, NameTable
, ParserContext
.NamespaceManager
);
661 } catch (Exception ex
) { // FIXME: (wishlist) better exception handling ;-(
662 HandleError ("List type value contains one or more invalid values.", ex
);
667 AssessStringValid (itemSimpleType
, itemSimpleType
.Datatype
, each
);
670 case XmlSchemaDerivationMethod
.Union
:
671 XmlSchemaSimpleTypeUnion union
= st
.Content
as XmlSchemaSimpleTypeUnion
;
673 string each
= normalized
;
674 // validate against ValidatedItemType
676 foreach (object eachType
in union
.ValidatedTypes
) {
677 itemDatatype
= eachType
as XmlSchemaDatatype
;
678 itemSimpleType
= eachType
as XmlSchemaSimpleType
;
679 if (itemDatatype
!= null) {
681 itemDatatype
.ParseValue (each
, NameTable
, ParserContext
.NamespaceManager
);
682 } catch (Exception
) { // FIXME: (wishlist) better exception handling ;-(
688 AssessStringValid (itemSimpleType
, itemSimpleType
.Datatype
, each
);
689 } catch (XmlSchemaException
) {
697 HandleError ("Union type value contains one or more invalid values.");
702 case XmlSchemaDerivationMethod
.Restriction
:
703 XmlSchemaSimpleTypeRestriction str
= st
.Content
as XmlSchemaSimpleTypeRestriction
;
706 /* Don't forget to validate against inherited type's facets
707 * Could we simplify this by assuming that the basetype will also
710 // mmm, will check later.
711 XmlSchemaSimpleType baseType
= st
.BaseXmlSchemaType
as XmlSchemaSimpleType
;
712 if (baseType
!= null) {
713 AssessStringValid(baseType
, dt
, normalized
);
715 if (!str
.ValidateValueWithFacets (normalized
, NameTable
)) {
716 HandleError ("Specified value was invalid against the facets.");
720 validatedDatatype
= st
.Datatype
;
724 if (validatedDatatype
!= null) {
726 validatedDatatype
.ParseValue (value, NameTable
, ParserContext
.NamespaceManager
);
727 } catch (Exception ex
) { // FIXME: (wishlist) It is bad manner ;-(
728 HandleError ("Invalidly typed data was specified.", ex
);
733 private object GetLocalTypeDefinition (string name
)
735 object xsiType
= null;
736 XmlQualifiedName typeQName
= QualifyName (name
);
737 if (typeQName
== XmlSchemaComplexType
.AnyTypeName
)
738 xsiType
= XmlSchemaComplexType
.AnyType
;
739 else if (XmlSchemaUtil
.IsBuiltInDatatypeName (typeQName
))
740 xsiType
= XmlSchemaDatatype
.FromName (typeQName
);
742 xsiType
= FindType (typeQName
);
746 // It is common to ElementLocallyValid::4 and SchemaValidityAssessment::1.2.1.2.4
747 private void AssessLocalTypeDerivationOK (object xsiType
, object baseType
, XmlSchemaDerivationMethod flag
)
749 XmlSchemaType xsiSchemaType
= xsiType
as XmlSchemaType
;
750 XmlSchemaComplexType baseComplexType
= baseType
as XmlSchemaComplexType
;
751 XmlSchemaComplexType xsiComplexType
= xsiSchemaType
as XmlSchemaComplexType
;
752 if (xsiType
!= baseType
) {
753 // Extracted (not extraneous) check for 3.4.6 TypeDerivationOK.
754 if (baseComplexType
!= null)
755 flag
|= baseComplexType
.BlockResolved
;
756 if (flag
== XmlSchemaDerivationMethod
.All
) {
757 HandleError ("Prohibited element type substitution.");
759 } else if (xsiSchemaType
!= null && (flag
& xsiSchemaType
.DerivedBy
) != 0) {
760 HandleError ("Prohibited element type substitution.");
765 if (xsiComplexType
!= null)
767 xsiComplexType
.ValidateTypeDerivationOK (baseType
, null, null);
768 } catch (XmlSchemaException ex
) {
769 // HandleError ("Locally specified schema complex type derivation failed. " + ex.Message, ex);
773 XmlSchemaSimpleType xsiSimpleType
= xsiType
as XmlSchemaSimpleType
;
774 if (xsiSimpleType
!= null) {
776 xsiSimpleType
.ValidateTypeDerivationOK (baseType
, null, null, true);
777 } catch (XmlSchemaException ex
) {
778 // HandleError ("Locally specified schema simple type derivation failed. " + ex.Message, ex);
782 else if (xsiType
is XmlSchemaDatatype
) {
786 HandleError ("Primitive data type cannot be derived type using xsi:type specification.");
790 // Section 3.3.4 of the spec.
791 private void AssessStartElementSchemaValidity ()
793 // If the reader is inside xsi:nil (and failed on validation),
794 // then simply skip its content.
795 if (xsiNilDepth
>= 0 && xsiNilDepth
< reader
.Depth
)
796 HandleError ("Element item appeared, while current element context is nil.");
798 context
.Load (reader
.Depth
);
799 if (childParticleState
!= null) {
800 context
.ParticleState
= childParticleState
;
801 childParticleState
= null;
804 // If validation state exists, then first assess particle validity.
805 context
.SchemaType
= null;
806 if (context
.ParticleState
!= null) {
807 ValidateStartElementParticle ();
810 string xsiNilValue
= reader
.GetAttribute ("nil", XmlSchema
.InstanceNamespace
);
811 if (xsiNilValue
!= null)
812 xsiNilValue
= xsiNilValue
.Trim (XmlChar
.WhitespaceChars
);
813 bool isXsiNil
= xsiNilValue
== "true";
814 if (isXsiNil
&& this.xsiNilDepth
< 0)
815 xsiNilDepth
= reader
.Depth
;
817 // [Schema Validity Assessment (Element) 1.2]
818 // Evaluate "local type definition" from xsi:type.
819 // (See spec 3.3.4 Schema Validity Assessment (Element) 1.2.1.2.3.
820 // Note that Schema Validity Assessment(Element) 1.2 takes
821 // precedence than 1.1 of that.
823 string xsiTypeName
= reader
.GetAttribute ("type", XmlSchema
.InstanceNamespace
);
824 if (xsiTypeName
!= null) {
825 xsiTypeName
= xsiTypeName
.Trim (XmlChar
.WhitespaceChars
);
826 object xsiType
= GetLocalTypeDefinition (xsiTypeName
);
828 HandleError ("The instance type was not found: " + xsiTypeName
+ " .");
830 XmlSchemaType xsiSchemaType
= xsiType
as XmlSchemaType
;
831 if (xsiSchemaType
!= null && this.context
.Element
!= null) {
832 XmlSchemaType elemBaseType
= context
.Element
.ElementType
as XmlSchemaType
;
833 if (elemBaseType
!= null && (xsiSchemaType
.DerivedBy
& elemBaseType
.FinalResolved
) != 0)
834 HandleError ("The instance type is prohibited by the type of the context element.");
835 if (elemBaseType
!= xsiType
&& (xsiSchemaType
.DerivedBy
& this.context
.Element
.BlockResolved
) != 0)
836 HandleError ("The instance type is prohibited by the context element.");
838 XmlSchemaComplexType xsiComplexType
= xsiType
as XmlSchemaComplexType
;
839 if (xsiComplexType
!= null && xsiComplexType
.IsAbstract
)
840 HandleError ("The instance type is abstract: " + xsiTypeName
+ " .");
842 // If current schema type exists, then this xsi:type must be
843 // valid extension of that type. See 1.2.1.2.4.
844 if (context
.Element
!= null) {
845 AssessLocalTypeDerivationOK (xsiType
, context
.Element
.ElementType
, context
.Element
.BlockResolved
);
847 AssessStartElementLocallyValidType (xsiType
); // 1.2.2:
848 context
.LocalTypeDefinition
= xsiType
;
853 context
.LocalTypeDefinition
= null;
855 // Create Validation Root, if not exist.
856 // [Schema Validity Assessment (Element) 1.1]
857 if (context
.Element
== null)
858 context
.Element
= FindElement (reader
.LocalName
, reader
.NamespaceURI
);
859 if (context
.Element
!= null) {
860 if (xsiTypeName
== null) {
861 context
.SchemaType
= context
.Element
.ElementType
;
862 AssessElementLocallyValidElement (context
.Element
, xsiNilValue
); // 1.1.2
866 switch (stateManager
.ProcessContents
) {
867 case XmlSchemaContentProcessing
.Skip
:
869 case XmlSchemaContentProcessing
.Lax
:
871 schema = schemas [reader.NamespaceURI];
872 if (schema != null && !schema.missedSubComponents)
873 HandleError ("Element declaration for " + reader.LocalName + " is missing.");
877 if (xsiTypeName
== null &&
878 (schemas
.Contains (reader
.NamespaceURI
) ||
879 !schemas
.MissedSubComponents (reader
.NamespaceURI
)))
880 HandleError ("Element declaration for " + reader
.LocalName
+ " is missing.");
885 if (stateManager
.ProcessContents
== XmlSchemaContentProcessing
.Skip
)
886 skipValidationDepth
= reader
.Depth
;
888 // Finally, create child particle state.
889 XmlSchemaComplexType xsComplexType
= SchemaType
as XmlSchemaComplexType
;
890 if (xsComplexType
!= null)
891 childParticleState
= stateManager
.Create (xsComplexType
.ValidatableParticle
);
892 else if (stateManager
.ProcessContents
== XmlSchemaContentProcessing
.Lax
)
893 childParticleState
= stateManager
.Create (XmlSchemaAny
.AnyTypeContent
);
895 childParticleState
= stateManager
.Create (XmlSchemaParticle
.Empty
);
897 AssessStartIdentityConstraints ();
899 context
.PushScope (reader
.Depth
);
902 // 3.3.4 Element Locally Valid (Element)
903 private void AssessElementLocallyValidElement (XmlSchemaElement element
, string xsiNilValue
)
905 XmlQualifiedName qname
= new XmlQualifiedName (reader
.LocalName
, reader
.NamespaceURI
);
908 HandleError ("Element declaration is required for " + qname
);
910 if (element
.ActualIsAbstract
)
911 HandleError ("Abstract element declaration was specified for " + qname
);
913 if (!element
.ActualIsNillable
&& xsiNilValue
!= null)
914 HandleError ("This element declaration is not nillable: " + qname
);
916 // Note that 3.2.1 xsi:nil constraints are to be validated in
917 else if (xsiNilValue
== "true") {
918 // AssessElementSchemaValidity() and ValidateCharacters()
920 if (element
.ValidatedFixedValue
!= null)
921 HandleError ("Schema instance nil was specified, where the element declaration for " + qname
+ "has fixed value constraints.");
924 string xsiType
= reader
.GetAttribute ("type", XmlSchema
.InstanceNamespace
);
925 if (xsiType
!= null) {
926 context
.LocalTypeDefinition
= GetLocalTypeDefinition (xsiType
);
927 AssessLocalTypeDerivationOK (context
.LocalTypeDefinition
, element
.ElementType
, element
.BlockResolved
);
930 context
.LocalTypeDefinition
= null;
932 // 5 Not all things cannot be assessed here.
933 // It is common to 5.1 and 5.2
934 if (element
.ElementType
!= null)
935 AssessStartElementLocallyValidType (SchemaType
);
937 // 6. should be out from here.
938 // See invokation of AssessStartIdentityConstraints().
940 // 7 is going to be validated in Read() (in case of xmlreader's EOF).
943 // 3.3.4 Element Locally Valid (Type)
944 private void AssessStartElementLocallyValidType (object schemaType
)
946 if (schemaType
== null) { // 1.
947 HandleError ("Schema type does not exist.");
950 XmlSchemaComplexType cType
= schemaType
as XmlSchemaComplexType
;
951 XmlSchemaSimpleType sType
= schemaType
as XmlSchemaSimpleType
;
954 while (reader
.MoveToNextAttribute ()) {
955 if (reader
.NamespaceURI
== XmlNamespaceManager
.XmlnsXmlns
)
957 if (reader
.NamespaceURI
!= XmlSchema
.InstanceNamespace
)
958 HandleError ("Current simple type cannot accept attributes other than schema instance namespace.");
959 switch (reader
.LocalName
) {
962 case "schemaLocation":
963 case "noNamespaceSchemaLocation":
966 HandleError ("Unknown schema instance namespace attribute: " + reader
.LocalName
);
970 reader
.MoveToElement ();
971 // 3.1.2 and 3.1.3 cannot be assessed here.
972 } else if (cType
!= null) {
973 if (cType
.IsAbstract
) { // 2.
974 HandleError ("Target complex type is abstract.");
978 AssessElementLocallyValidComplexType (cType
);
982 // 3.4.4 Element Locally Valid (Complex Type)
983 private void AssessElementLocallyValidComplexType (XmlSchemaComplexType cType
)
986 if (cType
.IsAbstract
)
987 HandleError ("Target complex type is abstract.");
989 // 2 (xsi:nil and content prohibition)
990 // See AssessStartElementSchemaValidity() and ValidateCharacters()
992 string elementNs
= reader
.NamespaceURI
;
993 // 3. attribute uses and
995 while (reader
.MoveToNextAttribute ()) {
996 if (reader
.NamespaceURI
== "http://www.w3.org/2000/xmlns/")
998 else if (reader
.NamespaceURI
== XmlSchema
.InstanceNamespace
)
1000 XmlQualifiedName qname
= new XmlQualifiedName (reader
.LocalName
, reader
.NamespaceURI
);
1001 XmlSchemaObject attMatch
= FindAttributeDeclaration (cType
, qname
, elementNs
);
1002 if (attMatch
== null)
1003 HandleError ("Attribute declaration was not found for " + qname
);
1005 XmlSchemaAttribute attdecl
= attMatch
as XmlSchemaAttribute
;
1006 if (attdecl
== null) { // i.e. anyAttribute
1007 XmlSchemaAnyAttribute anyAttrMatch
= attMatch
as XmlSchemaAnyAttribute
;
1009 AssessAttributeLocallyValidUse (attdecl
);
1010 AssessAttributeLocallyValid (attdecl
, true);
1014 reader
.MoveToElement ();
1016 // Collect default attributes.
1018 foreach (DictionaryEntry entry
in cType
.AttributeUses
) {
1019 XmlSchemaAttribute attr
= (XmlSchemaAttribute
) entry
.Value
;
1020 if (reader
[attr
.QualifiedName
.Name
, attr
.QualifiedName
.Namespace
] == null) {
1021 if (attr
.ValidatedUse
== XmlSchemaUse
.Required
&&
1022 attr
.ValidatedFixedValue
== null)
1023 HandleError ("Required attribute " + attr
.QualifiedName
+ " was not found.");
1024 else if (attr
.ValidatedDefaultValue
!= null)
1025 DefaultAttributesCache
.Add (attr
);
1026 else if (attr
.ValidatedFixedValue
!= null)
1027 DefaultAttributesCache
.Add (attr
);
1030 defaultAttributes
= (XmlSchemaAttribute
[])
1031 DefaultAttributesCache
.ToArray (typeof (XmlSchemaAttribute
));
1032 context
.DefaultAttributes
= defaultAttributes
;
1033 if (defaultAttributesCache
!= null)
1034 defaultAttributesCache
.Clear ();
1035 // 5. wild IDs was already checked above.
1038 // Spec 3.10.4 Item Valid (Wildcard)
1039 private bool AttributeWildcardItemValid (XmlSchemaAnyAttribute anyAttr
, XmlQualifiedName qname
)
1041 if (anyAttr
.HasValueAny
)
1043 if (anyAttr
.HasValueOther
&& (anyAttr
.TargetNamespace
== "" || reader
.NamespaceURI
!= anyAttr
.TargetNamespace
))
1045 if (anyAttr
.HasValueTargetNamespace
&& reader
.NamespaceURI
== anyAttr
.TargetNamespace
)
1047 if (anyAttr
.HasValueLocal
&& reader
.NamespaceURI
== "")
1049 for (int i
= 0; i
< anyAttr
.ResolvedNamespaces
.Count
; i
++)
1050 if (anyAttr
.ResolvedNamespaces
[i
] == reader
.NamespaceURI
)
1055 private XmlSchemaObject
FindAttributeDeclaration (
1056 XmlSchemaComplexType cType
,
1057 XmlQualifiedName qname
,
1060 XmlSchemaObject result
= cType
.AttributeUses
[qname
];
1063 if (cType
.AttributeWildcard
== null)
1066 if (!AttributeWildcardItemValid (cType
.AttributeWildcard
, qname
))
1069 if (cType
.AttributeWildcard
.ResolvedProcessContents
== XmlSchemaContentProcessing
.Skip
)
1070 return cType
.AttributeWildcard
;
1071 XmlSchemaAttribute attr
= schemas
.GlobalAttributes
[qname
] as XmlSchemaAttribute
;
1074 if (cType
.AttributeWildcard
.ResolvedProcessContents
== XmlSchemaContentProcessing
.Lax
)
1075 return cType
.AttributeWildcard
;
1080 // 3.2.4 Attribute Locally Valid and 3.4.4 - 5.wildIDs
1081 private void AssessAttributeLocallyValid (XmlSchemaAttribute attr
, bool checkWildIDs
)
1084 switch (reader
.NamespaceURI
) {
1085 case XmlNamespaceManager
.XmlnsXml
:
1086 case XmlNamespaceManager
.XmlnsXmlns
:
1087 case XmlSchema
.InstanceNamespace
:
1091 if (attr
.AttributeType
== null)
1092 HandleError ("Attribute type is missing for " + attr
.QualifiedName
);
1093 XmlSchemaDatatype dt
= attr
.AttributeType
as XmlSchemaDatatype
;
1095 dt
= ((XmlSchemaSimpleType
) attr
.AttributeType
).Datatype
;
1096 // It is a bit heavy process, so let's omit as long as possible ;-)
1097 if (dt
!= XmlSchemaSimpleType
.AnySimpleType
|| attr
.ValidatedFixedValue
!= null) {
1098 string normalized
= dt
.Normalize (reader
.Value
);
1099 object parsedValue
= null;
1101 parsedValue
= dt
.ParseValue (normalized
, reader
.NameTable
, this.ParserContext
.NamespaceManager
);
1102 } catch (Exception ex
) { // FIXME: (wishlist) It is bad manner ;-(
1103 HandleError ("Attribute value is invalid against its data type " + dt
.TokenizedType
, ex
);
1105 if (attr
.ValidatedFixedValue
!= null && attr
.ValidatedFixedValue
!= normalized
)
1106 HandleError ("The value of the attribute " + attr
.QualifiedName
+ " does not match with its fixed value.");
1108 AssessEachAttributeIdentityConstraint (dt
, normalized
, parsedValue
);
1112 private void AssessEachAttributeIdentityConstraint (XmlSchemaDatatype dt
,
1113 string normalized
, object parsedValue
)
1115 // Get normalized value and (if required) parsedValue if missing.
1116 switch (dt
.TokenizedType
) {
1117 case XmlTokenizedType
.IDREFS
:
1118 if (normalized
== null)
1119 normalized
= dt
.Normalize (reader
.Value
);
1120 if (parsedValue
== null)
1121 parsedValue
= dt
.ParseValue (normalized
, reader
.NameTable
, ParserContext
.NamespaceManager
);
1123 case XmlTokenizedType
.ID
:
1124 case XmlTokenizedType
.IDREF
:
1125 if (normalized
== null)
1126 normalized
= dt
.Normalize (reader
.Value
);
1130 // Validate identity constraints.
1131 switch (dt
.TokenizedType
) {
1132 case XmlTokenizedType
.ID
:
1133 if (thisElementId
!= null)
1134 HandleError ("ID type attribute was already assigned in the containing element.");
1135 thisElementId
= normalized
;
1136 if (idList
.Contains (normalized
))
1137 HandleError ("Duplicate ID value was found.");
1139 idList
.Add (normalized
, normalized
);
1140 if (MissingIDReferences
.Contains (normalized
))
1141 MissingIDReferences
.Remove (normalized
);
1143 case XmlTokenizedType
.IDREF
:
1144 if (!idList
.Contains (normalized
))
1145 MissingIDReferences
.Add (normalized
);
1147 case XmlTokenizedType
.IDREFS
:
1148 string [] idrefs
= (string []) parsedValue
;
1149 for (int i
= 0; i
< idrefs
.Length
; i
++) {
1150 string id
= idrefs
[i
];
1151 if (!idList
.Contains (id
))
1152 MissingIDReferences
.Add (id
);
1158 private void AssessAttributeLocallyValidUse (XmlSchemaAttribute attr
)
1160 // This is extra check than spec 3.5.4
1161 if (attr
.ValidatedUse
== XmlSchemaUse
.Prohibited
)
1162 HandleError ("Attribute " + attr
.QualifiedName
+ " is prohibited in this context.");
1165 private void AssessEndElementSchemaValidity ()
1167 if (childParticleState
== null)
1168 childParticleState
= context
.ParticleState
;
1169 ValidateEndElementParticle (); // validate against childrens' state.
1171 if (shouldValidateCharacters
) {
1172 ValidateEndCharacters ();
1173 shouldValidateCharacters
= false;
1176 // 3.3.4 Assess ElementLocallyValidElement 5: value constraints.
1177 // 3.3.4 Assess ElementLocallyValidType 3.1.3. = StringValid(3.14.4)
1178 // => ValidateEndCharacters().
1180 // Reset Identity constraints.
1181 for (int i
= 0; i
< keyTables
.Count
; i
++) {
1182 XsdKeyTable keyTable
= this.keyTables
[i
] as XsdKeyTable
;
1183 if (keyTable
.StartDepth
== reader
.Depth
) {
1184 EndIdentityValidation (keyTable
);
1186 for (int k
= 0; k
< keyTable
.Entries
.Count
; k
++) {
1187 XsdKeyEntry entry
= keyTable
.Entries
[k
] as XsdKeyEntry
;
1188 // Remove finished (maybe key not found) entries.
1189 if (entry
.StartDepth
== reader
.Depth
) {
1191 keyTable
.FinishedEntries
.Add (entry
);
1192 else if (entry
.KeySequence
.SourceSchemaIdentity
is XmlSchemaKey
)
1193 HandleError ("Key sequence is missing.");
1194 keyTable
.Entries
.RemoveAt (k
);
1197 // Pop validated key depth to find two or more fields.
1199 for (int j
= 0; j
< entry
.KeyFields
.Count
; j
++) {
1200 XsdKeyEntryField kf
= entry
.KeyFields
[j
];
1201 if (!kf
.FieldFound
&& kf
.FieldFoundDepth
== reader
.Depth
) {
1202 kf
.FieldFoundDepth
= 0;
1203 kf
.FieldFoundPath
= null;
1210 for (int i
= 0; i
< keyTables
.Count
; i
++) {
1211 XsdKeyTable keyseq
= this.keyTables
[i
] as XsdKeyTable
;
1212 if (keyseq
.StartDepth
== reader
.Depth
) {
1213 keyTables
.RemoveAt (i
);
1218 // Reset xsi:nil, if required.
1219 if (xsiNilDepth
== reader
.Depth
)
1223 // 3.11.4 Identity Constraint Satisfied
1224 private void AssessStartIdentityConstraints ()
1226 if (tmpKeyrefPool
!= null)
1227 tmpKeyrefPool
.Clear ();
1228 if (context
.Element
!= null && context
.Element
.Constraints
.Count
> 0) {
1229 // (a) Create new key sequences, if required.
1230 for (int i
= 0; i
< context
.Element
.Constraints
.Count
; i
++) {
1231 XmlSchemaIdentityConstraint ident
= (XmlSchemaIdentityConstraint
) context
.Element
.Constraints
[i
];
1232 XsdKeyTable seq
= CreateNewKeyTable (ident
);
1233 if (ident
is XmlSchemaKeyref
) {
1234 if (tmpKeyrefPool
== null)
1235 tmpKeyrefPool
= new ArrayList ();
1236 tmpKeyrefPool
.Add (seq
);
1241 // (b) Evaluate current key sequences.
1242 for (int i
= 0; i
< keyTables
.Count
; i
++) {
1243 XsdKeyTable seq
= (XsdKeyTable
) keyTables
[i
];
1244 if (seq
.SelectorMatches (this.elementQNameStack
, reader
) != null) {
1245 // creates and registers new entry.
1246 XsdKeyEntry entry
= new XsdKeyEntry (seq
, reader
);
1247 seq
.Entries
.Add (entry
);
1251 // (c) Evaluate field paths.
1252 for (int i
= 0; i
< keyTables
.Count
; i
++) {
1253 XsdKeyTable seq
= (XsdKeyTable
) keyTables
[i
];
1254 // If possible, create new field entry candidates.
1255 for (int j
= 0; j
< seq
.Entries
.Count
; j
++) {
1256 XsdKeyEntry entry
= seq
.Entries
[j
] as XsdKeyEntry
;
1258 entry
.FieldMatches (this.elementQNameStack
, this);
1259 } catch (Exception ex
) { // FIXME: (wishlist) It is bad manner ;-(
1260 HandleError ("Identity field value is invalid against its data type.", ex
);
1266 private XsdKeyTable
CreateNewKeyTable (XmlSchemaIdentityConstraint ident
)
1268 XsdKeyTable seq
= new XsdKeyTable (ident
, this);
1269 seq
.StartDepth
= reader
.Depth
;
1270 XmlSchemaKeyref keyref
= ident
as XmlSchemaKeyref
;
1271 this.keyTables
.Add (seq
);
1275 private void EndIdentityValidation (XsdKeyTable seq
)
1277 ArrayList errors
= new ArrayList ();
1278 for (int i
= 0; i
< seq
.Entries
.Count
; i
++) {
1279 XsdKeyEntry entry
= (XsdKeyEntry
) seq
.Entries
[i
];
1282 if (seq
.SourceSchemaIdentity
is XmlSchemaKey
)
1283 errors
.Add ("line " + entry
.SelectorLineNumber
+ "position " + entry
.SelectorLinePosition
);
1285 if (errors
.Count
> 0)
1286 HandleError ("Invalid identity constraints were found. Key was not found. "
1287 + String
.Join (", ", errors
.ToArray (typeof (string)) as string []));
1290 // Find reference target
1291 XmlSchemaKeyref xsdKeyref
= seq
.SourceSchemaIdentity
as XmlSchemaKeyref
;
1292 if (xsdKeyref
!= null) {
1293 for (int i
= this.keyTables
.Count
- 1; i
>= 0; i
--) {
1294 XsdKeyTable target
= this.keyTables
[i
] as XsdKeyTable
;
1295 if (target
.SourceSchemaIdentity
== xsdKeyref
.Target
) {
1296 seq
.ReferencedKey
= target
;
1297 for (int j
= 0; j
< seq
.FinishedEntries
.Count
; j
++) {
1298 XsdKeyEntry entry
= (XsdKeyEntry
) seq
.FinishedEntries
[j
];
1299 for (int k
= 0; k
< target
.FinishedEntries
.Count
; k
++) {
1300 XsdKeyEntry targetEntry
= (XsdKeyEntry
) target
.FinishedEntries
[k
];
1301 if (entry
.CompareIdentity (targetEntry
)) {
1302 entry
.KeyRefFound
= true;
1309 if (seq
.ReferencedKey
== null)
1310 HandleError ("Target key was not found.");
1311 for (int i
= 0; i
< seq
.FinishedEntries
.Count
; i
++) {
1312 XsdKeyEntry entry
= (XsdKeyEntry
) seq
.FinishedEntries
[i
];
1313 if (!entry
.KeyRefFound
)
1314 errors
.Add (" line " + entry
.SelectorLineNumber
+ ", position " + entry
.SelectorLinePosition
);
1316 if (errors
.Count
> 0)
1317 HandleError ("Invalid identity constraints were found. Referenced key was not found: "
1318 + String
.Join (" / ", errors
.ToArray (typeof (string)) as string []));
1322 // Overrided Methods
1324 public override void Close ()
1329 public override string GetAttribute (int i
)
1331 switch (reader
.NodeType
) {
1332 case XmlNodeType
.XmlDeclaration
:
1333 case XmlNodeType
.DocumentType
:
1334 return reader
.GetAttribute (i
);
1337 if (reader
.AttributeCount
> i
)
1338 reader
.GetAttribute (i
);
1339 int defIdx
= i
- nonDefaultAttributeCount
;
1340 if (i
< AttributeCount
)
1341 return defaultAttributes
[defIdx
].DefaultValue
;
1343 throw new ArgumentOutOfRangeException ("i", i
, "Specified attribute index is out of range.");
1346 public override string GetAttribute (string name
)
1348 switch (reader
.NodeType
) {
1349 case XmlNodeType
.XmlDeclaration
:
1350 case XmlNodeType
.DocumentType
:
1351 return reader
.GetAttribute (name
);
1354 string value = reader
.GetAttribute (name
);
1358 XmlQualifiedName qname
= SplitQName (name
);
1359 return GetDefaultAttribute (qname
.Name
, qname
.Namespace
);
1362 private XmlQualifiedName
SplitQName (string name
)
1364 if (!XmlChar
.IsName (name
))
1365 throw new ArgumentException ("Invalid name was specified.", "name");
1367 Exception ex
= null;
1368 XmlQualifiedName qname
= XmlSchemaUtil
.ToQName (reader
, name
, out ex
);
1370 return XmlQualifiedName
.Empty
;
1375 public override string GetAttribute (string localName
, string ns
)
1377 switch (reader
.NodeType
) {
1378 case XmlNodeType
.XmlDeclaration
:
1379 case XmlNodeType
.DocumentType
:
1380 return reader
.GetAttribute (localName
, ns
);
1383 string value = reader
.GetAttribute (localName
, ns
);
1387 return GetDefaultAttribute (localName
, ns
);
1390 private string GetDefaultAttribute (string localName
, string ns
)
1392 int idx
= this.FindDefaultAttribute (localName
, ns
);
1395 string value = defaultAttributes
[idx
].ValidatedDefaultValue
;
1397 value = defaultAttributes
[idx
].ValidatedFixedValue
;
1401 private int FindDefaultAttribute (string localName
, string ns
)
1403 for (int i
= 0; i
< this.defaultAttributes
.Length
; i
++) {
1404 XmlSchemaAttribute attr
= defaultAttributes
[i
];
1405 if (attr
.QualifiedName
.Name
== localName
&&
1406 (ns
== null || attr
.QualifiedName
.Namespace
== ns
))
1412 bool IXmlLineInfo
.HasLineInfo ()
1414 return readerLineInfo
!= null && readerLineInfo
.HasLineInfo ();
1417 public override string LookupNamespace (string prefix
)
1419 return reader
.LookupNamespace (prefix
);
1422 string IXmlNamespaceResolver
.LookupNamespace (string prefix
, bool atomizedNames
)
1424 IXmlNamespaceResolver res
= reader
as IXmlNamespaceResolver
;
1426 return res
.LookupNamespace (prefix
, atomizedNames
);
1428 return reader
.LookupNamespace (prefix
);
1431 public override void MoveToAttribute (int i
)
1433 switch (reader
.NodeType
) {
1434 case XmlNodeType
.XmlDeclaration
:
1435 case XmlNodeType
.DocumentType
:
1436 reader
.MoveToAttribute (i
);
1440 currentQName
= null;
1441 if (i
< this.nonDefaultAttributeCount
) {
1442 reader
.MoveToAttribute (i
);
1443 this.currentDefaultAttribute
= -1;
1444 this.defaultAttributeConsumed
= false;
1447 if (i
< AttributeCount
) {
1448 this.currentDefaultAttribute
= i
- nonDefaultAttributeCount
;
1449 this.defaultAttributeConsumed
= false;
1452 throw new ArgumentOutOfRangeException ("i", i
, "Attribute index is out of range.");
1455 public override bool MoveToAttribute (string name
)
1457 switch (reader
.NodeType
) {
1458 case XmlNodeType
.XmlDeclaration
:
1459 case XmlNodeType
.DocumentType
:
1460 return reader
.MoveToAttribute (name
);
1463 currentQName
= null;
1464 bool b
= reader
.MoveToAttribute (name
);
1466 this.currentDefaultAttribute
= -1;
1467 this.defaultAttributeConsumed
= false;
1471 return MoveToDefaultAttribute (name
, null);
1474 public override bool MoveToAttribute (string localName
, string ns
)
1476 switch (reader
.NodeType
) {
1477 case XmlNodeType
.XmlDeclaration
:
1478 case XmlNodeType
.DocumentType
:
1479 return reader
.MoveToAttribute (localName
, ns
);
1482 currentQName
= null;
1483 bool b
= reader
.MoveToAttribute (localName
, ns
);
1485 this.currentDefaultAttribute
= -1;
1486 this.defaultAttributeConsumed
= false;
1490 return MoveToDefaultAttribute (localName
, ns
);
1493 private bool MoveToDefaultAttribute (string localName
, string ns
)
1495 int idx
= this.FindDefaultAttribute (localName
, ns
);
1498 currentDefaultAttribute
= idx
;
1499 defaultAttributeConsumed
= false;
1503 public override bool MoveToElement ()
1505 currentDefaultAttribute
= -1;
1506 defaultAttributeConsumed
= false;
1507 currentQName
= null;
1508 return reader
.MoveToElement ();
1511 public override bool MoveToFirstAttribute ()
1513 switch (reader
.NodeType
) {
1514 case XmlNodeType
.XmlDeclaration
:
1515 case XmlNodeType
.DocumentType
:
1516 return reader
.MoveToFirstAttribute ();
1519 currentQName
= null;
1520 if (this.nonDefaultAttributeCount
> 0) {
1521 bool b
= reader
.MoveToFirstAttribute ();
1523 currentDefaultAttribute
= -1;
1524 defaultAttributeConsumed
= false;
1529 if (this.defaultAttributes
.Length
> 0) {
1530 currentDefaultAttribute
= 0;
1531 defaultAttributeConsumed
= false;
1538 public override bool MoveToNextAttribute ()
1540 switch (reader
.NodeType
) {
1541 case XmlNodeType
.XmlDeclaration
:
1542 case XmlNodeType
.DocumentType
:
1543 return reader
.MoveToNextAttribute ();
1546 currentQName
= null;
1547 if (currentDefaultAttribute
>= 0) {
1548 if (defaultAttributes
.Length
== currentDefaultAttribute
+ 1)
1550 currentDefaultAttribute
++;
1551 defaultAttributeConsumed
= false;
1555 bool b
= reader
.MoveToNextAttribute ();
1557 currentDefaultAttribute
= -1;
1558 defaultAttributeConsumed
= false;
1562 if (defaultAttributes
.Length
> 0) {
1563 currentDefaultAttribute
= 0;
1564 defaultAttributeConsumed
= false;
1571 private void ExamineAdditionalSchema ()
1573 XmlSchema schema
= null;
1574 string schemaLocation
= reader
.GetAttribute ("schemaLocation", XmlSchema
.InstanceNamespace
);
1575 bool schemaAdded
= false;
1576 if (schemaLocation
!= null) {
1577 string [] tmp
= null;
1579 schemaLocation
= XmlSchemaDatatype
.FromName ("token", XmlSchema
.Namespace
).Normalize (schemaLocation
);
1580 tmp
= schemaLocation
.Split (XmlChar
.WhitespaceChars
);
1581 } catch (Exception ex
) {
1582 HandleError ("Invalid schemaLocation attribute format.", ex
, true);
1583 tmp
= new string [0];
1585 if (tmp
.Length
% 2 != 0)
1586 HandleError ("Invalid schemaLocation attribute format.");
1587 for (int i
= 0; i
< tmp
.Length
; i
+= 2) {
1589 XmlTextReader xtr
= null;
1591 absUri
= new Uri ((this.BaseURI
!= "" ? new Uri (BaseURI
) : null), tmp
[i
+ 1]);
1592 xtr
= new XmlTextReader (absUri
.ToString ());
1593 schema
= XmlSchema
.Read (xtr
, null);
1594 } catch (Exception
) { // FIXME: (wishlist) It is bad manner ;-(
1595 HandleError ("Could not resolve schema location URI: " + absUri
, null, true);
1601 if (schema
.TargetNamespace
== null)
1602 schema
.TargetNamespace
= tmp
[i
];
1603 else if (schema
.TargetNamespace
!= tmp
[i
])
1604 HandleError ("Specified schema has different target namespace.");
1607 if (schema
!= null) {
1608 if (!schemas
.Contains (schema
.TargetNamespace
)) {
1610 schemas
.Add (schema
);
1614 string noNsSchemaLocation
= reader
.GetAttribute ("noNamespaceSchemaLocation", XmlSchema
.InstanceNamespace
);
1615 if (noNsSchemaLocation
!= null) {
1617 XmlTextReader xtr
= null;
1619 absUri
= new Uri ((this.BaseURI
!= "" ? new Uri (BaseURI
) : null), noNsSchemaLocation
);
1620 xtr
= new XmlTextReader (absUri
.ToString ());
1621 schema
= XmlSchema
.Read (xtr
, null);
1622 } catch (Exception
) { // FIXME: (wishlist) It is bad manner ;-(
1623 HandleError ("Could not resolve schema location URI: " + absUri
, null, true);
1628 if (schema
!= null && schema
.TargetNamespace
!= null)
1629 HandleError ("Specified schema has different target namespace.");
1631 if (schema
!= null) {
1632 if (!schemas
.Contains (schema
.TargetNamespace
)) {
1634 schemas
.Add (schema
);
1637 // FIXME: should call Reprocess()?
1642 private bool HasMissingIDReferences ()
1644 return missingIDReferences
!= null
1645 && missingIDReferences
.Count
> 0;
1648 public override bool Read ()
1650 nonDefaultAttributeCount
= 0;
1651 currentDefaultAttribute
= -1;
1652 defaultAttributeConsumed
= false;
1653 currentQName
= null;
1654 thisElementId
= null;
1655 defaultAttributes
= new XmlSchemaAttribute
[0];
1657 elementQNameStack
.RemoveAt (elementQNameStack
.Count
- 1);
1661 bool result
= reader
.Read ();
1662 // 3.3.4 ElementLocallyValidElement 7 = Root Valid.
1663 if (!result
&& HasMissingIDReferences ())
1664 HandleError ("There are missing ID references: " +
1666 this.missingIDReferences
.ToArray (typeof (string)) as string []));
1668 switch (reader
.NodeType
) {
1669 case XmlNodeType
.XmlDeclaration
:
1670 this.nonDefaultAttributeCount
= reader
.AttributeCount
;
1672 case XmlNodeType
.Element
:
1673 nonDefaultAttributeCount
= reader
.AttributeCount
;
1675 // FIXME: schemaLocation could be specified
1677 if (reader
.Depth
== 0)
1678 ExamineAdditionalSchema ();
1680 this.elementQNameStack
.Add (new XmlQualifiedName (reader
.LocalName
, reader
.NamespaceURI
));
1682 // If there is no schema information, then no validation is performed.
1683 if (schemas
.Count
== 0)
1686 if (skipValidationDepth
< 0 || reader
.Depth
<= skipValidationDepth
) {
1687 if (shouldValidateCharacters
) {
1688 ValidateEndCharacters ();
1689 shouldValidateCharacters
= false;
1691 AssessStartElementSchemaValidity ();
1692 storedCharacters
.Length
= 0;
1697 if (reader
.IsEmptyElement
)
1698 goto case XmlNodeType
.EndElement
;
1700 shouldValidateCharacters
= true;
1702 case XmlNodeType
.EndElement
:
1703 if (reader
.Depth
== skipValidationDepth
) {
1704 skipValidationDepth
= -1;
1708 AssessEndElementSchemaValidity ();
1710 storedCharacters
.Length
= 0;
1711 childParticleState
= null;
1715 case XmlNodeType
.CDATA
:
1716 case XmlNodeType
.SignificantWhitespace
:
1717 case XmlNodeType
.Text
:
1718 XmlSchemaComplexType ct
= context
.ActualType
as XmlSchemaComplexType
;
1719 if (ct
!= null && storedCharacters
.Length
> 0) {
1720 switch (ct
.ContentType
) {
1721 case XmlSchemaContentType
.ElementOnly
:
1722 case XmlSchemaContentType
.Empty
:
1723 HandleError ("Not allowed character content was found.");
1728 ValidateCharacters ();
1735 public override bool ReadAttributeValue ()
1737 if (currentDefaultAttribute
< 0)
1738 return reader
.ReadAttributeValue ();
1740 if (this.defaultAttributeConsumed
)
1743 defaultAttributeConsumed
= true;
1748 public override string ReadInnerXml ()
1750 // MS.NET 1.0 has a serious bug here. It skips validation.
1751 return reader
.ReadInnerXml ();
1754 public override string ReadOuterXml ()
1756 // MS.NET 1.0 has a serious bug here. It skips validation.
1757 return reader
.ReadOuterXml ();
1761 // XmlReader.ReadString() should call derived this.Read().
1762 public override string ReadString ()
1765 return reader
.ReadString ();
1767 return base.ReadString ();
1771 // This class itself does not have this feature.
1772 public override void ResolveEntity ()
1774 reader
.ResolveEntity ();
1777 internal class XsdValidationContext
1779 Hashtable contextStack
;
1781 public XsdValidationContext ()
1783 contextStack
= new Hashtable ();
1786 // Some of them might be missing (See the spec section 5.3, and also 3.3.4).
1787 public XmlSchemaElement Element
;
1788 public XsdValidationState ParticleState
;
1789 public XmlSchemaAttribute
[] DefaultAttributes
;
1791 // Some of them might be missing (See the spec section 5.3).
1792 public object SchemaType
;
1794 public object LocalTypeDefinition
;
1796 public object ActualType
{
1798 if (LocalTypeDefinition
!= null)
1799 return LocalTypeDefinition
;
1805 public void Clear ()
1809 ParticleState
= null;
1810 LocalTypeDefinition
= null;
1813 public void PushScope (int depth
)
1815 contextStack
[depth
] = this.MemberwiseClone ();
1818 public void PopScope (int depth
)
1821 contextStack
.Remove (depth
+ 1);
1824 public void Load (int depth
)
1827 XsdValidationContext restored
= (XsdValidationContext
) contextStack
[depth
];
1828 if (restored
!= null) {
1829 this.Element
= restored
.Element
;
1830 this.ParticleState
= restored
.ParticleState
;
1831 this.SchemaType
= restored
.SchemaType
;
1832 this.LocalTypeDefinition
= restored
.LocalTypeDefinition
;