//
// (C)2003 Atsushi Enomoto
//
-// Note:
-//
-// This class doesn't support set_XmlResolver, since it isn't common to XmlReader interface.
-// Try to set that of xml reader which is used to construct this object.
-//
//
// Permission is hereby granted, free of charge, to any person obtaining
using System;
using System.Collections;
using System.Collections.Specialized;
+using System.IO;
using System.Text;
using System.Xml;
using System.Xml.Schema;
using Mono.Xml;
+#if NET_2_0
+using ValException = System.Xml.Schema.XmlSchemaValidationException;
+#else
+using ValException = System.Xml.Schema.XmlSchemaException;
+#endif
+
+using QName = System.Xml.XmlQualifiedName;
+using ContentProc = System.Xml.Schema.XmlSchemaContentProcessing;
+using XsElement = System.Xml.Schema.XmlSchemaElement;
+using XsAttribute = System.Xml.Schema.XmlSchemaAttribute;
+using ComplexType = System.Xml.Schema.XmlSchemaComplexType;
+using SimpleType = System.Xml.Schema.XmlSchemaSimpleType;
+using SimpleTypeRest = System.Xml.Schema.XmlSchemaSimpleTypeRestriction;
+using SimpleTypeList = System.Xml.Schema.XmlSchemaSimpleTypeList;
+using SimpleTypeUnion = System.Xml.Schema.XmlSchemaSimpleTypeUnion;
+using XsDatatype = System.Xml.Schema.XmlSchemaDatatype;
+
namespace Mono.Xml.Schema
{
internal class XsdValidatingReader : XmlReader, IXmlLineInfo, IHasXmlSchemaInfo, IHasXmlParserContext, IXmlNamespaceResolver
{
- static char [] wsChars = new char [] {' ', '\t', '\n', '\r'};
+ static readonly XsAttribute [] emptyAttributeArray =
+ new XsAttribute [0];
XmlReader reader;
XmlResolver resolver;
XmlSchemaSet schemas = new XmlSchemaSet ();
bool namespaces = true;
+#region ID Constraints
bool checkIdentity = true;
- Hashtable idList = new Hashtable ();
- ArrayList missingIDReferences;
- string thisElementId;
+ XsdIDManager idManager = new XsdIDManager ();
+#endregion
+#region Key Constraints
+ bool checkKeyConstraints = true;
ArrayList keyTables = new ArrayList ();
ArrayList currentKeyFieldConsumers;
+ ArrayList tmpKeyrefPool;
+#endregion
+ ArrayList elementQNameStack = new ArrayList ();
- XsdValidationStateManager stateManager = new XsdValidationStateManager ();
- XsdValidationContext context = new XsdValidationContext ();
+ XsdParticleStateManager state = new XsdParticleStateManager ();
+ int skipValidationDepth = -1;
int xsiNilDepth = -1;
StringBuilder storedCharacters = new StringBuilder ();
bool shouldValidateCharacters;
- int skipValidationDepth = -1;
- XmlSchemaAttribute [] defaultAttributes = new XmlSchemaAttribute [0];
+ XsAttribute [] defaultAttributes = emptyAttributeArray;
int currentDefaultAttribute = -1;
- XmlQualifiedName currentQName;
-
- ArrayList elementQNameStack = new ArrayList ();
- bool popContext;
-
- // Property Cache.
- bool defaultAttributeConsumed;
-
- // Validation engine cached object
ArrayList defaultAttributesCache = new ArrayList ();
- ArrayList tmpKeyrefPool;
+ bool defaultAttributeConsumed;
+ object currentAttrType;
#region .ctor
public XsdValidatingReader (XmlReader reader)
this.reader = reader;
readerLineInfo = reader as IXmlLineInfo;
sourceReaderSchemaInfo = reader as IHasXmlSchemaInfo;
+ schemas.ValidationEventHandler += ValidationEventHandler;
}
#endregion
public ValidationEventHandler ValidationEventHandler;
// Private Properties
- private XmlQualifiedName CurrentQName {
- get {
- if (currentQName == null)
- currentQName = new XmlQualifiedName (LocalName, NamespaceURI);
- return currentQName;
- }
+
+ private XsdValidationContext Context {
+ get { return state.Context; }
}
+#region Key Constraints
internal ArrayList CurrentKeyFieldConsumers {
get {
if (currentKeyFieldConsumers == null)
return currentKeyFieldConsumers;
}
}
-
- private ArrayList MissingIDReferences {
- get {
- if (missingIDReferences == null)
- missingIDReferences = new ArrayList ();
- return missingIDReferences;
- }
- }
+#endregion
// Public Non-overrides
set { namespaces = value; }
}
- public XmlReader Reader {
- get { return reader; }
- }
-
// This is required to resolve xsi:schemaLocation
public XmlResolver XmlResolver {
set {
switch (NodeType) {
case XmlNodeType.Element:
- if (context.ActualType != null)
- return context.ActualType;
- else if (context.Element != null)
- return context.Element.ElementType;
+ if (Context.ActualType != null)
+ return Context.ActualType;
else
return SourceReaderSchemaType;
case XmlNodeType.Attribute:
- XmlSchemaComplexType ct = context.ActualType as XmlSchemaComplexType;
- if (ct != null) {
- XmlSchemaAttribute attdef = ct.AttributeUses [CurrentQName] as XmlSchemaAttribute;
- if (attdef != null)
- return attdef.AttributeType;
+ if (currentAttrType == null) {
+ ComplexType ct = Context.ActualType as ComplexType;
+ if (ct != null) {
+ XsAttribute attdef = ct.AttributeUses [new QName (LocalName, NamespaceURI)] as XsAttribute;
+ if (attdef != null)
+ currentAttrType = attdef.AttributeType;
+ return currentAttrType;
+ }
+ currentAttrType = SourceReaderSchemaType;
}
- return SourceReaderSchemaType;
+ return currentAttrType;
default:
return SourceReaderSchemaType;
}
// It is used only for independent XmlReader use, not for XmlValidatingReader.
#if NET_2_0
+ [Obsolete]
public override object ReadTypedValue ()
#else
public object ReadTypedValue ()
#endif
{
- XmlSchemaDatatype dt = SchemaType as XmlSchemaDatatype;
- XmlSchemaSimpleType st = SchemaType as XmlSchemaSimpleType;
+ object o = XmlSchemaUtil.ReadTypedValue (this,
+ SchemaType, ParserContext.NamespaceManager,
+ storedCharacters);
+ storedCharacters.Length = 0;
+ return o;
+ }
+
+ private object ReadTypedValueCore ()
+ {
+ XsDatatype dt = SchemaType as XsDatatype;
+ SimpleType st = SchemaType as SimpleType;
if (st != null)
dt = st.Datatype;
if (dt == null)
return null;
}
- // Public Overrided Properties
+ // Public Overriden Properties
public override int AttributeCount {
get {
get { return GetAttribute (localName, ns); }
}
- int IXmlLineInfo.LineNumber {
+ public int LineNumber {
get { return readerLineInfo != null ? readerLineInfo.LineNumber : 0; }
}
- int IXmlLineInfo.LinePosition {
+ public int LinePosition {
get { return readerLineInfo != null ? readerLineInfo.LinePosition : 0; }
}
if (defaultAttributeConsumed)
return String.Empty;
- XmlQualifiedName qname = defaultAttributes [currentDefaultAttribute].QualifiedName;
+ QName qname = defaultAttributes [currentDefaultAttribute].QualifiedName;
string prefix = Prefix;
if (prefix == String.Empty)
return qname.Name;
return reader.Prefix;
if (defaultAttributeConsumed)
return String.Empty;
- XmlQualifiedName qname = defaultAttributes [currentDefaultAttribute].QualifiedName;
+ QName qname = defaultAttributes [currentDefaultAttribute].QualifiedName;
string prefix = this.ParserContext.NamespaceManager.LookupPrefix (qname.Namespace, false);
if (prefix == null)
return String.Empty;
// Private Methods
- private XmlQualifiedName QualifyName (string name)
- {
- return XmlQualifiedName.Parse (name, this);
- }
-
private void HandleError (string error)
{
HandleError (error, null);
if (ValidationType == ValidationType.None) // extra quick check
return;
- XmlSchemaException schemaException = new XmlSchemaException (error,
+ ValException schemaException = new ValException (error,
this, this.BaseURI, null, innerException);
HandleError (schemaException, isWarning);
}
- private void HandleError (XmlSchemaException schemaException)
+ private void HandleError (ValException schemaException)
{
HandleError (schemaException, false);
}
- private void HandleError (XmlSchemaException schemaException, bool isWarning)
+ private void HandleError (ValException schemaException, bool isWarning)
{
if (ValidationType == ValidationType.None)
return;
throw e.Exception;
}
- private XmlSchemaElement FindElement (string name, string ns)
+ private XsElement FindElement (string name, string ns)
{
- return (XmlSchemaElement) schemas.GlobalElements [new XmlQualifiedName (name, ns)];
+ return (XsElement) schemas.GlobalElements [new QName (name, ns)];
}
- private XmlSchemaType FindType (XmlQualifiedName qname)
+ private XmlSchemaType FindType (QName qname)
{
return (XmlSchemaType) schemas.GlobalTypes [qname];
}
private void ValidateStartElementParticle ()
{
- stateManager.CurrentElement = null;
- context.SiblingState =
- context.SiblingState.EvaluateStartElement (
- reader.LocalName, reader.NamespaceURI);
- if (context.SiblingState == XsdValidationState.Invalid)
+ if (Context.State == null)
+ return;
+ Context.XsiType = null;
+ state.CurrentElement = null;
+ Context.EvaluateStartElement (reader.LocalName,
+ reader.NamespaceURI);
+ if (Context.IsInvalid)
HandleError ("Invalid start element: " + reader.NamespaceURI + ":" + reader.LocalName);
- context.Element = stateManager.CurrentElement;
- if (context.Element != null)
- context.SchemaType = context.Element.ElementType;
+ Context.SetElement (state.CurrentElement);
}
private void ValidateEndElementParticle ()
{
- if (context.ChildState != null) {
- if (!context.ChildState.EvaluateEndElement ()) {
+ if (Context.State != null) {
+ if (!Context.EvaluateEndElement ()) {
HandleError ("Invalid end element: " + reader.Name);
}
}
- context.PopScope (reader.Depth);
+ state.PopContext ();
}
// Utility for missing validation completion related to child items.
if (xsiNilDepth >= 0 && xsiNilDepth < reader.Depth)
HandleError ("Element item appeared, while current element context is nil.");
- storedCharacters.Append (reader.Value);
+ if (shouldValidateCharacters)
+ storedCharacters.Append (reader.Value);
}
// Utility for missing validation completion related to child items.
- private void ValidateEndCharacters ()
+ private void ValidateEndSimpleContent ()
{
- if (context.ActualType == null)
+ if (shouldValidateCharacters)
+ ValidateEndSimpleContentCore ();
+ shouldValidateCharacters = false;
+ storedCharacters.Length = 0;
+ }
+
+ private void ValidateEndSimpleContentCore ()
+ {
+ if (Context.ActualType == null)
return;
string value = storedCharacters.ToString ();
- if (storedCharacters.Length == 0) {
+ if (value.Length == 0) {
// 3.3.4 Element Locally Valid (Element) 5.1.2
- if (context.Element != null) {
- if (context.Element.ValidatedDefaultValue != null)
- value = context.Element.ValidatedDefaultValue;
+ if (Context.Element != null) {
+ if (Context.Element.ValidatedDefaultValue != null)
+ value = Context.Element.ValidatedDefaultValue;
}
}
- XmlSchemaDatatype dt = context.ActualType as XmlSchemaDatatype;
- XmlSchemaSimpleType st = context.ActualType as XmlSchemaSimpleType;
+ XsDatatype dt = Context.ActualType as XsDatatype;
+ SimpleType st = Context.ActualType as SimpleType;
if (dt == null) {
if (st != null) {
dt = st.Datatype;
} else {
- XmlSchemaComplexType ct = context.ActualType as XmlSchemaComplexType;
+ ComplexType ct = Context.ActualType as ComplexType;
dt = ct.Datatype;
switch (ct.ContentType) {
case XmlSchemaContentType.ElementOnly:
case XmlSchemaContentType.Empty:
- if (storedCharacters.Length > 0)
+ if (value.Length > 0)
HandleError ("Character content not allowed.");
break;
}
}
if (dt != null) {
// 3.3.4 Element Locally Valid (Element) :: 5.2.2.2. Fixed value constraints
- if (context.Element != null && context.Element.ValidatedFixedValue != null)
- if (value != context.Element.ValidatedFixedValue)
+ if (Context.Element != null && Context.Element.ValidatedFixedValue != null)
+ if (value != Context.Element.ValidatedFixedValue)
HandleError ("Fixed value constraint was not satisfied.");
AssessStringValid (st, dt, value);
}
- // Identity field value
- if (currentKeyFieldConsumers != null) {
- while (this.currentKeyFieldConsumers.Count > 0) {
- XsdKeyEntryField field = this.currentKeyFieldConsumers [0] as XsdKeyEntryField;
- if (field.Identity != null)
- HandleError ("Two or more identical field was found. Former value is '" + field.Identity + "' .");
- object identity = null; // This means empty value
- if (dt != null) {
- try {
- identity = dt.ParseValue (value, NameTable, ParserContext.NamespaceManager);
- } catch (Exception ex) { // FIXME: (wishlist) This is bad manner ;-(
- HandleError ("Identity value is invalid against its data type " + dt.TokenizedType, ex);
- }
- }
- if (identity == null)
- identity = value;
-
- if (!field.SetIdentityField (identity, reader.Depth == xsiNilDepth, dt as XsdAnySimpleType, this))
- HandleError ("Two or more identical key value was found: '" + value + "' .");
- this.currentKeyFieldConsumers.RemoveAt (0);
- }
- }
+#region Key Constraints
+ if (checkKeyConstraints)
+ ValidateSimpleContentIdentity (dt, value);
+#endregion
shouldValidateCharacters = false;
}
// 3.14.4 String Valid
- private void AssessStringValid (XmlSchemaSimpleType st,
- XmlSchemaDatatype dt, string value)
+ private void AssessStringValid (SimpleType st,
+ XsDatatype dt, string value)
{
- XmlSchemaDatatype validatedDatatype = dt;
+ XsDatatype validatedDatatype = dt;
if (st != null) {
string normalized = validatedDatatype.Normalize (value);
string [] values;
- XmlSchemaDatatype itemDatatype;
- XmlSchemaSimpleType itemSimpleType;
+ XsDatatype itemDatatype;
+ SimpleType itemSimpleType;
switch (st.DerivedBy) {
case XmlSchemaDerivationMethod.List:
- XmlSchemaSimpleTypeList listContent = st.Content as XmlSchemaSimpleTypeList;
- values = normalized.Split (wsChars);
- itemDatatype = listContent.ValidatedListItemType as XmlSchemaDatatype;
- itemSimpleType = listContent.ValidatedListItemType as XmlSchemaSimpleType;
+ SimpleTypeList listContent = st.Content as SimpleTypeList;
+ values = normalized.Split (XmlChar.WhitespaceChars);
+ itemDatatype = listContent.ValidatedListItemType as XsDatatype;
+ itemSimpleType = listContent.ValidatedListItemType as SimpleType;
for (int vi = 0; vi < values.Length; vi++) {
string each = values [vi];
if (each == String.Empty)
}
break;
case XmlSchemaDerivationMethod.Union:
- XmlSchemaSimpleTypeUnion union = st.Content as XmlSchemaSimpleTypeUnion;
+ SimpleTypeUnion union = st.Content as SimpleTypeUnion;
{
string each = normalized;
// validate against ValidatedItemType
bool passed = false;
foreach (object eachType in union.ValidatedTypes) {
- itemDatatype = eachType as XmlSchemaDatatype;
- itemSimpleType = eachType as XmlSchemaSimpleType;
+ itemDatatype = eachType as XsDatatype;
+ itemSimpleType = eachType as SimpleType;
if (itemDatatype != null) {
try {
itemDatatype.ParseValue (each, NameTable, ParserContext.NamespaceManager);
else {
try {
AssessStringValid (itemSimpleType, itemSimpleType.Datatype, each);
- } catch (XmlSchemaException) {
+ } catch (ValException) {
continue;
}
}
}
break;
case XmlSchemaDerivationMethod.Restriction:
- XmlSchemaSimpleTypeRestriction str = st.Content as XmlSchemaSimpleTypeRestriction;
+ SimpleTypeRest str = st.Content as SimpleTypeRest;
// facet validation
if (str != null) {
/* Don't forget to validate against inherited type's facets
* be restriction?
* */
// mmm, will check later.
- XmlSchemaSimpleType baseType = st.BaseXmlSchemaType as XmlSchemaSimpleType;
+ SimpleType baseType = st.BaseXmlSchemaType as SimpleType;
if (baseType != null) {
AssessStringValid(baseType, dt, normalized);
}
}
}
- private object GetLocalTypeDefinition (string name)
+ private object GetXsiType (string name)
{
object xsiType = null;
- XmlQualifiedName typeQName = QualifyName (name);
- if (typeQName == XmlSchemaComplexType.AnyTypeName)
- xsiType = XmlSchemaComplexType.AnyType;
+ QName typeQName = QName.Parse (name, this);
+ if (typeQName == ComplexType.AnyTypeName)
+ xsiType = ComplexType.AnyType;
else if (XmlSchemaUtil.IsBuiltInDatatypeName (typeQName))
- xsiType = XmlSchemaDatatype.FromName (typeQName);
+ xsiType = XsDatatype.FromName (typeQName);
else
xsiType = FindType (typeQName);
return xsiType;
private void AssessLocalTypeDerivationOK (object xsiType, object baseType, XmlSchemaDerivationMethod flag)
{
XmlSchemaType xsiSchemaType = xsiType as XmlSchemaType;
- XmlSchemaComplexType baseComplexType = baseType as XmlSchemaComplexType;
- XmlSchemaComplexType xsiComplexType = xsiSchemaType as XmlSchemaComplexType;
+ ComplexType baseComplexType = baseType as ComplexType;
+ ComplexType xsiComplexType = xsiSchemaType as ComplexType;
if (xsiType != baseType) {
// Extracted (not extraneous) check for 3.4.6 TypeDerivationOK.
if (baseComplexType != null)
if (xsiComplexType != null)
try {
xsiComplexType.ValidateTypeDerivationOK (baseType, null, null);
- } catch (XmlSchemaException ex) {
+ } catch (ValException ex) {
// HandleError ("Locally specified schema complex type derivation failed. " + ex.Message, ex);
HandleError (ex);
}
else {
- XmlSchemaSimpleType xsiSimpleType = xsiType as XmlSchemaSimpleType;
+ SimpleType xsiSimpleType = xsiType as SimpleType;
if (xsiSimpleType != null) {
try {
xsiSimpleType.ValidateTypeDerivationOK (baseType, null, null, true);
- } catch (XmlSchemaException ex) {
+ } catch (ValException ex) {
// HandleError ("Locally specified schema simple type derivation failed. " + ex.Message, ex);
HandleError (ex);
}
}
- else if (xsiType is XmlSchemaDatatype) {
+ else if (xsiType is XsDatatype) {
// do nothing
}
else
// Section 3.3.4 of the spec.
private void AssessStartElementSchemaValidity ()
{
- // If the reader is inside xsi:nil (and failed on validation),
- // then simply skip its content.
+ // If the reader is inside xsi:nil (and failed
+ // on validation), then simply skip its content.
if (xsiNilDepth >= 0 && xsiNilDepth < reader.Depth)
HandleError ("Element item appeared, while current element context is nil.");
- context.Load (reader.Depth);
- if (context.ChildState != null) {
- context.SiblingState = context.ChildState;
- context.ChildState = null;
- }
-
- // If validation state exists, then first assess particle validity.
- context.SchemaType = null;
- if (context.SiblingState != null) {
- ValidateStartElementParticle ();
- }
+ ValidateStartElementParticle ();
string xsiNilValue = reader.GetAttribute ("nil", XmlSchema.InstanceNamespace);
if (xsiNilValue != null)
string xsiTypeName = reader.GetAttribute ("type", XmlSchema.InstanceNamespace);
if (xsiTypeName != null) {
xsiTypeName = xsiTypeName.Trim (XmlChar.WhitespaceChars);
- object xsiType = GetLocalTypeDefinition (xsiTypeName);
+ object xsiType = GetXsiType (xsiTypeName);
if (xsiType == null)
HandleError ("The instance type was not found: " + xsiTypeName + " .");
else {
XmlSchemaType xsiSchemaType = xsiType as XmlSchemaType;
- if (xsiSchemaType != null && this.context.Element != null) {
- XmlSchemaType elemBaseType = context.Element.ElementType as XmlSchemaType;
+ if (xsiSchemaType != null && this.Context.Element != null) {
+ XmlSchemaType elemBaseType = Context.Element.ElementType as XmlSchemaType;
if (elemBaseType != null && (xsiSchemaType.DerivedBy & elemBaseType.FinalResolved) != 0)
HandleError ("The instance type is prohibited by the type of the context element.");
- if (elemBaseType != xsiType && (xsiSchemaType.DerivedBy & this.context.Element.BlockResolved) != 0)
+ if (elemBaseType != xsiType && (xsiSchemaType.DerivedBy & this.Context.Element.BlockResolved) != 0)
HandleError ("The instance type is prohibited by the context element.");
}
- XmlSchemaComplexType xsiComplexType = xsiType as XmlSchemaComplexType;
+ ComplexType xsiComplexType = xsiType as ComplexType;
if (xsiComplexType != null && xsiComplexType.IsAbstract)
HandleError ("The instance type is abstract: " + xsiTypeName + " .");
else {
// If current schema type exists, then this xsi:type must be
// valid extension of that type. See 1.2.1.2.4.
- if (context.Element != null) {
- AssessLocalTypeDerivationOK (xsiType, context.Element.ElementType, context.Element.BlockResolved);
+ if (Context.Element != null) {
+ AssessLocalTypeDerivationOK (xsiType, Context.Element.ElementType, Context.Element.BlockResolved);
}
AssessStartElementLocallyValidType (xsiType); // 1.2.2:
- context.LocalTypeDefinition = xsiType;
+ Context.XsiType = xsiType;
}
}
}
- else
- context.LocalTypeDefinition = null;
// Create Validation Root, if not exist.
// [Schema Validity Assessment (Element) 1.1]
- if (context.Element == null)
- context.Element = FindElement (reader.LocalName, reader.NamespaceURI);
- if (context.Element != null) {
- if (xsiTypeName == null) {
- context.SchemaType = context.Element.ElementType;
- AssessElementLocallyValidElement (context.Element, xsiNilValue); // 1.1.2
+ if (Context.Element == null) {
+ state.CurrentElement = FindElement (reader.LocalName, reader.NamespaceURI);
+ Context.SetElement (state.CurrentElement);
+ }
+ if (Context.Element != null) {
+ if (Context.XsiType == null) {
+ AssessElementLocallyValidElement (xsiNilValue); // 1.1.2
}
} else {
- switch (stateManager.ProcessContents) {
- case XmlSchemaContentProcessing.Skip:
+ switch (state.ProcessContents) {
+ case ContentProc.Skip:
break;
- case XmlSchemaContentProcessing.Lax:
- /*
- schema = schemas [reader.NamespaceURI];
- if (schema != null && !schema.missedSubComponents)
- HandleError ("Element declaration for " + reader.LocalName + " is missing.");
- */
+ case ContentProc.Lax:
break;
default:
if (xsiTypeName == null &&
(schemas.Contains (reader.NamespaceURI) ||
!schemas.MissedSubComponents (reader.NamespaceURI)))
- HandleError ("Element declaration for " + reader.LocalName + " is missing.");
+ HandleError ("Element declaration for " + new QName (reader.LocalName, reader.NamespaceURI) + " is missing.");
break;
}
}
- if (stateManager.ProcessContents
- == XmlSchemaContentProcessing.Skip)
+ state.PushContext ();
+
+ XsdValidationState next = null;
+ if (state.ProcessContents == ContentProc.Skip)
skipValidationDepth = reader.Depth;
else {
// create child particle state.
- XmlSchemaComplexType xsComplexType = SchemaType as XmlSchemaComplexType;
+ ComplexType xsComplexType = SchemaType as ComplexType;
if (xsComplexType != null)
- context.ChildState = stateManager.Create (xsComplexType.ValidatableParticle);
- else if (stateManager.ProcessContents == XmlSchemaContentProcessing.Lax)
- context.ChildState = stateManager.Create (XmlSchemaAny.AnyTypeContent);
+ next = state.Create (xsComplexType.ValidatableParticle);
+ else if (state.ProcessContents == ContentProc.Lax)
+ next = state.Create (XmlSchemaAny.AnyTypeContent);
else
- context.ChildState = stateManager.Create (XmlSchemaParticle.Empty);
+ next = state.Create (XmlSchemaParticle.Empty);
}
+ Context.State = next;
- AssessStartIdentityConstraints ();
+#region Key Constraints
+ if (checkKeyConstraints) {
+ ValidateKeySelectors ();
+ ValidateKeyFields ();
+ }
+#endregion
- context.PushScope (reader.Depth);
}
// 3.3.4 Element Locally Valid (Element)
- private void AssessElementLocallyValidElement (XmlSchemaElement element, string xsiNilValue)
+ private void AssessElementLocallyValidElement (string xsiNilValue)
{
- XmlQualifiedName qname = new XmlQualifiedName (reader.LocalName, reader.NamespaceURI);
+ XsElement element = Context.Element;
+ QName qname = new QName (reader.LocalName, reader.NamespaceURI);
// 1.
if (element == null)
HandleError ("Element declaration is required for " + qname);
if (!element.ActualIsNillable && xsiNilValue != null)
HandleError ("This element declaration is not nillable: " + qname);
// 3.2.
- // Note that 3.2.1 xsi:nil constraints are to be validated in
+ // Note that 3.2.1 xsi:nil constraints are to be
+ // validated in AssessElementSchemaValidity() and
+ // ValidateCharacters().
else if (xsiNilValue == "true") {
- // AssessElementSchemaValidity() and ValidateCharacters()
-
if (element.ValidatedFixedValue != null)
HandleError ("Schema instance nil was specified, where the element declaration for " + qname + "has fixed value constraints.");
}
- // 4.
+ // 4. xsi:type (it takes precedence than element type)
string xsiType = reader.GetAttribute ("type", XmlSchema.InstanceNamespace);
if (xsiType != null) {
- context.LocalTypeDefinition = GetLocalTypeDefinition (xsiType);
- AssessLocalTypeDerivationOK (context.LocalTypeDefinition, element.ElementType, element.BlockResolved);
+ Context.XsiType = GetXsiType (xsiType);
+ AssessLocalTypeDerivationOK (Context.XsiType, element.ElementType, element.BlockResolved);
}
else
- context.LocalTypeDefinition = null;
+ Context.XsiType = null;
// 5 Not all things cannot be assessed here.
// It is common to 5.1 and 5.2
HandleError ("Schema type does not exist.");
return;
}
- XmlSchemaComplexType cType = schemaType as XmlSchemaComplexType;
- XmlSchemaSimpleType sType = schemaType as XmlSchemaSimpleType;
+ ComplexType cType = schemaType as ComplexType;
+ SimpleType sType = schemaType as SimpleType;
if (sType != null) {
// 3.1.1.
while (reader.MoveToNextAttribute ()) {
}
// 3.4.4 Element Locally Valid (Complex Type)
- private void AssessElementLocallyValidComplexType (XmlSchemaComplexType cType)
+ private void AssessElementLocallyValidComplexType (ComplexType cType)
{
// 1.
if (cType.IsAbstract)
case XmlSchema.InstanceNamespace:
continue;
}
- XmlQualifiedName qname = new XmlQualifiedName (reader.LocalName, reader.NamespaceURI);
- XmlSchemaObject attMatch = FindAttributeDeclaration (cType, qname);
+ QName qname = new QName (reader.LocalName, reader.NamespaceURI);
+ // including 3.10.4 Item Valid (Wildcard)
+ XmlSchemaObject attMatch = XmlSchemaUtil.FindAttributeDeclaration (reader.NamespaceURI, schemas, cType, qname);
if (attMatch == null)
HandleError ("Attribute declaration was not found for " + qname);
- XmlSchemaAttribute attdecl = attMatch as XmlSchemaAttribute;
+ XsAttribute attdecl = attMatch as XsAttribute;
if (attdecl != null) {
AssessAttributeLocallyValidUse (attdecl);
AssessAttributeLocallyValid (attdecl);
// Collect default attributes.
// 4.
foreach (DictionaryEntry entry in cType.AttributeUses) {
- XmlSchemaAttribute attr = (XmlSchemaAttribute) entry.Value;
+ XsAttribute attr = (XsAttribute) entry.Value;
if (reader [attr.QualifiedName.Name, attr.QualifiedName.Namespace] == null) {
if (attr.ValidatedUse == XmlSchemaUse.Required &&
attr.ValidatedFixedValue == null)
defaultAttributesCache.Add (attr);
}
}
- defaultAttributes = (XmlSchemaAttribute [])
- defaultAttributesCache.ToArray (typeof (XmlSchemaAttribute));
- context.DefaultAttributes = defaultAttributes;
+ if (defaultAttributesCache.Count == 0)
+ defaultAttributes = emptyAttributeArray;
+ else
+ defaultAttributes = (XsAttribute [])
+ defaultAttributesCache.ToArray (
+ typeof (XsAttribute));
defaultAttributesCache.Clear ();
// 5. wild IDs was already checked above.
}
- // Spec 3.10.4 Item Valid (Wildcard)
- private static bool AttributeWildcardItemValid (XmlSchemaAnyAttribute anyAttr, XmlQualifiedName qname, string ns)
- {
- if (anyAttr.HasValueAny)
- return true;
- if (anyAttr.HasValueOther && (anyAttr.TargetNamespace == "" || ns != anyAttr.TargetNamespace))
- return true;
- if (anyAttr.HasValueTargetNamespace && ns == anyAttr.TargetNamespace)
- return true;
- if (anyAttr.HasValueLocal && ns == "")
- return true;
- for (int i = 0; i < anyAttr.ResolvedNamespaces.Count; i++)
- if (anyAttr.ResolvedNamespaces [i] == ns)
- return true;
- return false;
- }
-
- private XmlSchemaObject FindAttributeDeclaration (
- XmlSchemaComplexType cType,
- XmlQualifiedName qname)
- {
- XmlSchemaObject result = cType.AttributeUses [qname];
- if (result != null)
- return result;
- if (cType.AttributeWildcard == null)
- return null;
-
- if (!AttributeWildcardItemValid (cType.AttributeWildcard, qname, reader.NamespaceURI))
- return null;
-
- if (cType.AttributeWildcard.ResolvedProcessContents == XmlSchemaContentProcessing.Skip)
- return cType.AttributeWildcard;
- XmlSchemaAttribute attr = schemas.GlobalAttributes [qname] as XmlSchemaAttribute;
- if (attr != null)
- return attr;
- if (cType.AttributeWildcard.ResolvedProcessContents == XmlSchemaContentProcessing.Lax)
- return cType.AttributeWildcard;
- else
- return null;
- }
-
// 3.2.4 Attribute Locally Valid and 3.4.4
- private void AssessAttributeLocallyValid (XmlSchemaAttribute attr)
+ private void AssessAttributeLocallyValid (XsAttribute attr)
{
// 2. - 4.
if (attr.AttributeType == null)
HandleError ("Attribute type is missing for " + attr.QualifiedName);
- XmlSchemaDatatype dt = attr.AttributeType as XmlSchemaDatatype;
+ XsDatatype dt = attr.AttributeType as XsDatatype;
if (dt == null)
- dt = ((XmlSchemaSimpleType) attr.AttributeType).Datatype;
+ dt = ((SimpleType) attr.AttributeType).Datatype;
// It is a bit heavy process, so let's omit as long as possible ;-)
- if (dt != XmlSchemaSimpleType.AnySimpleType || attr.ValidatedFixedValue != null) {
+ if (dt != SimpleType.AnySimpleType || attr.ValidatedFixedValue != null) {
string normalized = dt.Normalize (reader.Value);
object parsedValue = null;
try {
HandleError ("The value of the attribute " + attr.QualifiedName + " does not match with its fixed value.");
parsedValue = dt.ParseValue (attr.ValidatedFixedValue, reader.NameTable, this.ParserContext.NamespaceManager);
}
- if (this.checkIdentity)
- AssessEachAttributeIdentityConstraint (dt, parsedValue);
- }
- }
-
- // 3.4.4-5 wild IDs
- private void AssessEachAttributeIdentityConstraint (
- XmlSchemaDatatype dt, object parsedValue)
- {
- // Validate identity constraints.
- string str = parsedValue as string;
- switch (dt.TokenizedType) {
- case XmlTokenizedType.ID:
- if (thisElementId != null)
- HandleError ("ID type attribute was already assigned in the containing element.");
- thisElementId = str;
- if (idList.Contains (str))
- HandleError ("Duplicate ID value was found.");
- else
- idList.Add (str, str);
- if (MissingIDReferences.Contains (str))
- MissingIDReferences.Remove (str);
- break;
- case XmlTokenizedType.IDREF:
- if (!idList.Contains (str))
- MissingIDReferences.Add (str);
- break;
- case XmlTokenizedType.IDREFS:
- string [] idrefs = (string []) parsedValue;
- for (int i = 0; i < idrefs.Length; i++) {
- string id = idrefs [i];
- if (!idList.Contains (id))
- MissingIDReferences.Add (id);
+#region ID Constraints
+ if (this.checkIdentity) {
+ string error = idManager.AssessEachAttributeIdentityConstraint (dt, parsedValue, ((QName) elementQNameStack [elementQNameStack.Count - 1]).Name);
+ if (error != null)
+ HandleError (error);
}
- break;
+#endregion
}
}
- private void AssessAttributeLocallyValidUse (XmlSchemaAttribute attr)
+ private void AssessAttributeLocallyValidUse (XsAttribute attr)
{
// This is extra check than spec 3.5.4
if (attr.ValidatedUse == XmlSchemaUse.Prohibited)
private void AssessEndElementSchemaValidity ()
{
- if (context.ChildState == null)
- context.ChildState =
- context.SiblingState;
ValidateEndElementParticle (); // validate against childrens' state.
- if (shouldValidateCharacters) {
- ValidateEndCharacters ();
- shouldValidateCharacters = false;
- }
+ ValidateEndSimpleContent ();
// 3.3.4 Assess ElementLocallyValidElement 5: value constraints.
// 3.3.4 Assess ElementLocallyValidType 3.1.3. = StringValid(3.14.4)
- // => ValidateEndCharacters().
+ // => ValidateEndSimpleContent().
+#region Key Constraints
+ if (checkKeyConstraints)
+ ValidateEndElementKeyConstraints ();
+#endregion
+
+ // Reset xsi:nil, if required.
+ if (xsiNilDepth == reader.Depth)
+ xsiNilDepth = -1;
+ }
+
+#region Key Constraints
+ private void ValidateEndElementKeyConstraints ()
+ {
// Reset Identity constraints.
for (int i = 0; i < keyTables.Count; i++) {
- XsdKeyTable keyTable = this.keyTables [i] as XsdKeyTable;
- if (keyTable.StartDepth == reader.Depth) {
- EndIdentityValidation (keyTable);
+ XsdKeyTable seq = this.keyTables [i] as XsdKeyTable;
+ if (seq.StartDepth == reader.Depth) {
+ EndIdentityValidation (seq);
} else {
- for (int k = 0; k < keyTable.Entries.Count; k++) {
- XsdKeyEntry entry = keyTable.Entries [k] as XsdKeyEntry;
+ for (int k = 0; k < seq.Entries.Count; k++) {
+ XsdKeyEntry entry = seq.Entries [k] as XsdKeyEntry;
// Remove finished (maybe key not found) entries.
if (entry.StartDepth == reader.Depth) {
if (entry.KeyFound)
- keyTable.FinishedEntries.Add (entry);
- else if (entry.KeySequence.SourceSchemaIdentity is XmlSchemaKey)
+ seq.FinishedEntries.Add (entry);
+ else if (seq.SourceSchemaIdentity is XmlSchemaKey)
HandleError ("Key sequence is missing.");
- keyTable.Entries.RemoveAt (k);
+ seq.Entries.RemoveAt (k);
k--;
}
// Pop validated key depth to find two or more fields.
}
}
for (int i = 0; i < keyTables.Count; i++) {
- XsdKeyTable keyseq = this.keyTables [i] as XsdKeyTable;
- if (keyseq.StartDepth == reader.Depth) {
+ XsdKeyTable seq = this.keyTables [i] as XsdKeyTable;
+ if (seq.StartDepth == reader.Depth) {
keyTables.RemoveAt (i);
i--;
}
}
-
- // Reset xsi:nil, if required.
- if (xsiNilDepth == reader.Depth)
- xsiNilDepth = -1;
}
// 3.11.4 Identity Constraint Satisfied
- private void AssessStartIdentityConstraints ()
+ private void ValidateKeySelectors ()
{
if (tmpKeyrefPool != null)
tmpKeyrefPool.Clear ();
- if (context.Element != null && context.Element.Constraints.Count > 0) {
+ if (Context.Element != null && Context.Element.Constraints.Count > 0) {
// (a) Create new key sequences, if required.
- for (int i = 0; i < context.Element.Constraints.Count; i++) {
- XmlSchemaIdentityConstraint ident = (XmlSchemaIdentityConstraint) context.Element.Constraints [i];
+ for (int i = 0; i < Context.Element.Constraints.Count; i++) {
+ XmlSchemaIdentityConstraint ident = (XmlSchemaIdentityConstraint) Context.Element.Constraints [i];
XsdKeyTable seq = CreateNewKeyTable (ident);
if (ident is XmlSchemaKeyref) {
if (tmpKeyrefPool == null)
// (b) Evaluate current key sequences.
for (int i = 0; i < keyTables.Count; i++) {
XsdKeyTable seq = (XsdKeyTable) keyTables [i];
- if (seq.SelectorMatches (this.elementQNameStack, reader) != null) {
+ if (seq.SelectorMatches (this.elementQNameStack, reader.Depth) != null) {
// creates and registers new entry.
- XsdKeyEntry entry = new XsdKeyEntry (seq, reader);
+ XsdKeyEntry entry = new XsdKeyEntry (seq, reader.Depth, readerLineInfo);
seq.Entries.Add (entry);
}
}
+ }
+ private void ValidateKeyFields ()
+ {
// (c) Evaluate field paths.
for (int i = 0; i < keyTables.Count; i++) {
XsdKeyTable seq = (XsdKeyTable) keyTables [i];
// If possible, create new field entry candidates.
for (int j = 0; j < seq.Entries.Count; j++) {
- XsdKeyEntry entry = seq.Entries [j] as XsdKeyEntry;
try {
- entry.FieldMatches (this.elementQNameStack, this);
- } catch (Exception ex) { // FIXME: (wishlist) It is bad manner ;-(
- HandleError ("Identity field value is invalid against its data type.", ex);
+ ProcessKeyEntry (seq.Entries [j]);
+ } catch (ValException ex) {
+ HandleError (ex);
}
}
}
}
+ private void ProcessKeyEntry (XsdKeyEntry entry)
+ {
+ bool isNil = XsiNilDepth == Depth;
+ entry.ProcessMatch (false, elementQNameStack, this, NameTable, BaseURI, SchemaType, ParserContext.NamespaceManager, readerLineInfo, Depth, null, null, null, isNil, CurrentKeyFieldConsumers);
+ if (MoveToFirstAttribute ()) {
+ try {
+ do {
+ switch (NamespaceURI) {
+ case XmlNamespaceManager.XmlnsXmlns:
+ case XmlSchema.InstanceNamespace:
+ continue;
+ }
+ entry.ProcessMatch (true, elementQNameStack, this, NameTable, BaseURI, SchemaType, ParserContext.NamespaceManager, readerLineInfo, Depth, LocalName, NamespaceURI, Value, false, CurrentKeyFieldConsumers);
+ } while (MoveToNextAttribute ());
+ } finally {
+ MoveToElement ();
+ }
+ }
+ }
+
private XsdKeyTable CreateNewKeyTable (XmlSchemaIdentityConstraint ident)
{
- XsdKeyTable seq = new XsdKeyTable (ident, this);
+ XsdKeyTable seq = new XsdKeyTable (ident);
seq.StartDepth = reader.Depth;
this.keyTables.Add (seq);
return seq;
}
+ private void ValidateSimpleContentIdentity (
+ XmlSchemaDatatype dt, string value)
+ {
+ // Identity field value
+ if (currentKeyFieldConsumers != null) {
+ while (this.currentKeyFieldConsumers.Count > 0) {
+ XsdKeyEntryField field = this.currentKeyFieldConsumers [0] as XsdKeyEntryField;
+ if (field.Identity != null)
+ HandleError ("Two or more identical field was found. Former value is '" + field.Identity + "' .");
+ object identity = null; // This means empty value
+ if (dt != null) {
+ try {
+ identity = dt.ParseValue (value, NameTable, ParserContext.NamespaceManager);
+ } catch (Exception ex) { // FIXME: (wishlist) This is bad manner ;-(
+ HandleError ("Identity value is invalid against its data type " + dt.TokenizedType, ex);
+ }
+ }
+ if (identity == null)
+ identity = value;
+
+ if (!field.SetIdentityField (identity, reader.Depth == xsiNilDepth, dt as XsdAnySimpleType, this.Depth, readerLineInfo))
+ HandleError ("Two or more identical key value was found: '" + value + "' .");
+ this.currentKeyFieldConsumers.RemoveAt (0);
+ }
+ }
+ }
+
private void EndIdentityValidation (XsdKeyTable seq)
{
- ArrayList errors = new ArrayList ();
+ ArrayList errors = null;
for (int i = 0; i < seq.Entries.Count; i++) {
XsdKeyEntry entry = (XsdKeyEntry) seq.Entries [i];
if (entry.KeyFound)
continue;
- if (seq.SourceSchemaIdentity is XmlSchemaKey)
+ if (seq.SourceSchemaIdentity is XmlSchemaKey) {
+ if (errors == null)
+ errors = new ArrayList ();
errors.Add ("line " + entry.SelectorLineNumber + "position " + entry.SelectorLinePosition);
+ }
}
- if (errors.Count > 0)
+ if (errors != null)
HandleError ("Invalid identity constraints were found. Key was not found. "
+ String.Join (", ", errors.ToArray (typeof (string)) as string []));
- errors.Clear ();
- // Find reference target
+ // If it is keyref, then find reference target
XmlSchemaKeyref xsdKeyref = seq.SourceSchemaIdentity as XmlSchemaKeyref;
- if (xsdKeyref != null) {
- for (int i = this.keyTables.Count - 1; i >= 0; i--) {
- XsdKeyTable target = this.keyTables [i] as XsdKeyTable;
- if (target.SourceSchemaIdentity == xsdKeyref.Target) {
- seq.ReferencedKey = target;
- for (int j = 0; j < seq.FinishedEntries.Count; j++) {
- XsdKeyEntry entry = (XsdKeyEntry) seq.FinishedEntries [j];
- for (int k = 0; k < target.FinishedEntries.Count; k++) {
- XsdKeyEntry targetEntry = (XsdKeyEntry) target.FinishedEntries [k];
- if (entry.CompareIdentity (targetEntry)) {
- entry.KeyRefFound = true;
- break;
- }
- }
+ if (xsdKeyref != null)
+ EndKeyrefValidation (seq, xsdKeyref.Target);
+ }
+
+ private void EndKeyrefValidation (XsdKeyTable seq, XmlSchemaIdentityConstraint targetIdent)
+ {
+ for (int i = this.keyTables.Count - 1; i >= 0; i--) {
+ XsdKeyTable target = this.keyTables [i] as XsdKeyTable;
+ if (target.SourceSchemaIdentity != targetIdent)
+ continue;
+ seq.ReferencedKey = target;
+ for (int j = 0; j < seq.FinishedEntries.Count; j++) {
+ XsdKeyEntry entry = (XsdKeyEntry) seq.FinishedEntries [j];
+ for (int k = 0; k < target.FinishedEntries.Count; k++) {
+ XsdKeyEntry targetEntry = (XsdKeyEntry) target.FinishedEntries [k];
+ if (entry.CompareIdentity (targetEntry)) {
+ entry.KeyRefFound = true;
+ break;
}
}
}
- if (seq.ReferencedKey == null)
- HandleError ("Target key was not found.");
- for (int i = 0; i < seq.FinishedEntries.Count; i++) {
- XsdKeyEntry entry = (XsdKeyEntry) seq.FinishedEntries [i];
- if (!entry.KeyRefFound)
- errors.Add (" line " + entry.SelectorLineNumber + ", position " + entry.SelectorLinePosition);
+ }
+ if (seq.ReferencedKey == null)
+ HandleError ("Target key was not found.");
+ ArrayList errors = null;
+ for (int i = 0; i < seq.FinishedEntries.Count; i++) {
+ XsdKeyEntry entry = (XsdKeyEntry) seq.FinishedEntries [i];
+ if (!entry.KeyRefFound) {
+ if (errors == null)
+ errors = new ArrayList ();
+ errors.Add (" line " + entry.SelectorLineNumber + ", position " + entry.SelectorLinePosition);
}
- if (errors.Count > 0)
- HandleError ("Invalid identity constraints were found. Referenced key was not found: "
- + String.Join (" / ", errors.ToArray (typeof (string)) as string []));
}
+ if (errors != null)
+ HandleError ("Invalid identity constraints were found. Referenced key was not found: "
+ + String.Join (" / ", errors.ToArray (typeof (string)) as string []));
}
+#endregion
// Overrided Methods
if (value != null)
return value;
- XmlQualifiedName qname = SplitQName (name);
+ QName qname = SplitQName (name);
return GetDefaultAttribute (qname.Name, qname.Namespace);
}
- private XmlQualifiedName SplitQName (string name)
+ private QName SplitQName (string name)
{
if (!XmlChar.IsName (name))
throw new ArgumentException ("Invalid name was specified.", "name");
Exception ex = null;
- XmlQualifiedName qname = XmlSchemaUtil.ToQName (reader, name, out ex);
+ QName qname = XmlSchemaUtil.ToQName (reader, name, out ex);
if (ex != null)
- return XmlQualifiedName.Empty;
+ return QName.Empty;
else
return qname;
}
private int FindDefaultAttribute (string localName, string ns)
{
for (int i = 0; i < this.defaultAttributes.Length; i++) {
- XmlSchemaAttribute attr = defaultAttributes [i];
+ XsAttribute attr = defaultAttributes [i];
if (attr.QualifiedName.Name == localName &&
(ns == null || attr.QualifiedName.Namespace == ns))
return i;
return -1;
}
- bool IXmlLineInfo.HasLineInfo ()
+ public bool HasLineInfo ()
{
return readerLineInfo != null && readerLineInfo.HasLineInfo ();
}
return;
}
- currentQName = null;
+ currentAttrType = null;
if (i < reader.AttributeCount) {
reader.MoveToAttribute (i);
this.currentDefaultAttribute = -1;
return reader.MoveToAttribute (name);
}
- currentQName = null;
+ currentAttrType = null;
bool b = reader.MoveToAttribute (name);
if (b) {
this.currentDefaultAttribute = -1;
return reader.MoveToAttribute (localName, ns);
}
- currentQName = null;
+ currentAttrType = null;
bool b = reader.MoveToAttribute (localName, ns);
if (b) {
this.currentDefaultAttribute = -1;
{
currentDefaultAttribute = -1;
defaultAttributeConsumed = false;
- currentQName = null;
+ currentAttrType = null;
return reader.MoveToElement ();
}
return reader.MoveToFirstAttribute ();
}
- currentQName = null;
+ currentAttrType = null;
if (reader.AttributeCount > 0) {
bool b = reader.MoveToFirstAttribute ();
if (b) {
return reader.MoveToNextAttribute ();
}
- currentQName = null;
+ currentAttrType = null;
if (currentDefaultAttribute >= 0) {
if (defaultAttributes.Length == currentDefaultAttribute + 1)
return false;
return false;
}
+ private XmlSchema ReadExternalSchema (string uri)
+ {
+ Uri absUri = resolver.ResolveUri ((BaseURI != "" ? new Uri (BaseURI) : null), uri);
+ string absUriString = absUri != null ? absUri.ToString () : String.Empty;
+ XmlTextReader xtr = null;
+ try {
+ xtr = new XmlTextReader (absUriString,
+ (Stream) resolver.GetEntity (
+ absUri, null, typeof (Stream)),
+ NameTable);
+ return XmlSchema.Read (
+ xtr, ValidationEventHandler);
+ } finally {
+ if (xtr != null)
+ xtr.Close ();
+ }
+ }
+
private void ExamineAdditionalSchema ()
{
+ if (resolver == null)
+ return;
XmlSchema schema = null;
string schemaLocation = reader.GetAttribute ("schemaLocation", XmlSchema.InstanceNamespace);
bool schemaAdded = false;
if (schemaLocation != null) {
string [] tmp = null;
try {
- schemaLocation = XmlSchemaDatatype.FromName ("token", XmlSchema.Namespace).Normalize (schemaLocation);
+ schemaLocation = XsDatatype.FromName ("token", XmlSchema.Namespace).Normalize (schemaLocation);
tmp = schemaLocation.Split (XmlChar.WhitespaceChars);
} catch (Exception ex) {
HandleError ("Invalid schemaLocation attribute format.", ex, true);
if (tmp.Length % 2 != 0)
HandleError ("Invalid schemaLocation attribute format.");
for (int i = 0; i < tmp.Length; i += 2) {
- Uri absUri = null;
- XmlTextReader xtr = null;
try {
- absUri = new Uri ((this.BaseURI != "" ? new Uri (BaseURI) : null), tmp [i + 1]);
- xtr = new XmlTextReader (absUri.ToString (), NameTable);
- schema = XmlSchema.Read (xtr, null);
+ schema = ReadExternalSchema (tmp [i + 1]);
} catch (Exception) { // FIXME: (wishlist) It is bad manner ;-(
- HandleError ("Could not resolve schema location URI: " + absUri, null, true);
+ HandleError ("Could not resolve schema location URI: " + tmp [i + 1], null, true);
continue;
- } finally {
- if (xtr != null)
- xtr.Close ();
}
if (schema.TargetNamespace == null)
schema.TargetNamespace = tmp [i];
schema = null;
string noNsSchemaLocation = reader.GetAttribute ("noNamespaceSchemaLocation", XmlSchema.InstanceNamespace);
if (noNsSchemaLocation != null) {
- Uri absUri = null;
- XmlTextReader xtr = null;
try {
- absUri = new Uri ((this.BaseURI != "" ? new Uri (BaseURI) : null), noNsSchemaLocation);
- xtr = new XmlTextReader (absUri.ToString (), NameTable);
- schema = XmlSchema.Read (xtr, null);
+ schema = ReadExternalSchema (noNsSchemaLocation);
} catch (Exception) { // FIXME: (wishlist) It is bad manner ;-(
- HandleError ("Could not resolve schema location URI: " + absUri, null, true);
- } finally {
- if (xtr != null)
- xtr.Close ();
+ HandleError ("Could not resolve schema location URI: " + noNsSchemaLocation, null, true);
}
if (schema != null && schema.TargetNamespace != null)
HandleError ("Specified schema has different target namespace.");
schemas.Compile ();
}
- private bool HasMissingIDReferences ()
- {
- return missingIDReferences != null
- && missingIDReferences.Count > 0;
- }
-
public override bool Read ()
{
currentDefaultAttribute = -1;
defaultAttributeConsumed = false;
- currentQName = null;
+ currentAttrType = null;
+#region ID Constraints
if (this.checkIdentity)
- thisElementId = null;
- defaultAttributes = new XmlSchemaAttribute [0];
- if (!schemas.IsCompiled)
- schemas.Compile ();
- if (popContext) {
- elementQNameStack.RemoveAt (elementQNameStack.Count - 1);
- popContext = false;
- }
+ idManager.OnStartElement ();
+#endregion
+ defaultAttributes = emptyAttributeArray;
bool result = reader.Read ();
+#region ID Constraints
// 3.3.4 ElementLocallyValidElement 7 = Root Valid.
if (!result && this.checkIdentity &&
- HasMissingIDReferences ())
- HandleError ("There are missing ID references: " +
- String.Join (" ",
- this.missingIDReferences.ToArray (typeof (string)) as string []));
+ idManager.HasMissingIDReferences ())
+ HandleError ("There are missing ID references: " + idManager.GetMissingIDString ());
+#endregion
+
+ // FIXME: schemaLocation could be specified
+ // at any Depth.
+ if (reader.Depth == 0 &&
+ reader.NodeType == XmlNodeType.Element)
+ ExamineAdditionalSchema ();
+ if (schemas.Count == 0)
+ return result;
+ if (!schemas.IsCompiled)
+ schemas.Compile ();
switch (reader.NodeType) {
case XmlNodeType.Element:
- // FIXME: schemaLocation could be specified
- // at any Depth.
- if (reader.Depth == 0)
- ExamineAdditionalSchema ();
-
- this.elementQNameStack.Add (new XmlQualifiedName (reader.LocalName, reader.NamespaceURI));
+#region Key Constraints
+ if (checkKeyConstraints)
+ this.elementQNameStack.Add (new QName (reader.LocalName, reader.NamespaceURI));
+#endregion
// If there is no schema information, then no validation is performed.
- if (schemas.Count == 0)
- break;
-
if (skipValidationDepth < 0 || reader.Depth <= skipValidationDepth) {
- if (shouldValidateCharacters) {
- ValidateEndCharacters ();
- shouldValidateCharacters = false;
- }
+ ValidateEndSimpleContent ();
AssessStartElementSchemaValidity ();
- storedCharacters.Length = 0;
- } else {
- context.Clear ();
}
if (reader.IsEmptyElement)
shouldValidateCharacters = true;
break;
case XmlNodeType.EndElement:
- if (reader.Depth == skipValidationDepth) {
+ if (reader.Depth == skipValidationDepth)
skipValidationDepth = -1;
- context.Clear ();
- }
- else
+ else if (skipValidationDepth < 0 || reader.Depth <= skipValidationDepth)
AssessEndElementSchemaValidity ();
- storedCharacters.Length = 0;
- context.ChildState = null;
- popContext = true;
+ if (checkKeyConstraints)
+ elementQNameStack.RemoveAt (elementQNameStack.Count - 1);
break;
case XmlNodeType.CDATA:
case XmlNodeType.SignificantWhitespace:
case XmlNodeType.Text:
- XmlSchemaComplexType ct = context.ActualType as XmlSchemaComplexType;
+ // FIXME: does this check make sense?
+ ComplexType ct = Context.ActualType as ComplexType;
if (ct != null && storedCharacters.Length > 0) {
switch (ct.ContentType) {
case XmlSchemaContentType.ElementOnly:
{
reader.ResolveEntity ();
}
+ }
- internal class XsdValidationContext
+ internal class XsdValidationContext
+ {
+ public XsdValidationContext ()
{
- Hashtable contextStack;
+ }
+
+ // Some of them might be missing (See the spec section 5.3, and also 3.3.4).
+ public XsElement Element;
+ public object XsiType; // xsi:type
+ internal XsdValidationState State;
+
+ // Note that it represents current element's type.
+ public object ActualType {
+ get {
+ if (XsiType != null)
+ return XsiType;
+ else
+ return Element != null ? Element.ElementType : null;
+ }
+ }
- public XsdValidationContext ()
- {
- contextStack = new Hashtable ();
+#if NET_2_0
+ public XmlSchemaType ActualSchemaType {
+ get {
+ object at = ActualType;
+ if (at == null)
+ return null;
+ XmlSchemaType st = at as XmlSchemaType;
+ if (st == null)
+ st = XmlSchemaType.GetBuiltInSimpleType (
+ ((XmlSchemaDatatype) at).TypeCode);
+ return st;
}
+ }
+#endif
- // Some of them might be missing (See the spec section 5.3, and also 3.3.4).
- public XmlSchemaElement Element;
- public XsdValidationState SiblingState;
- public XsdValidationState ChildState;
- public XmlSchemaAttribute [] DefaultAttributes;
+ public bool IsInvalid {
+ get { return State == XsdValidationState.Invalid; }
+ }
- // Some of them might be missing (See the spec section 5.3).
- public object SchemaType;
+ public object Clone ()
+ {
+ return MemberwiseClone ();
+ }
- public object LocalTypeDefinition;
+ public void EvaluateStartElement (
+ string localName, string ns)
+ {
+ State = State.EvaluateStartElement (localName, ns);
+ }
- public object ActualType {
- get {
- if (LocalTypeDefinition != null)
- return LocalTypeDefinition;
- else
- return SchemaType;
- }
- }
+ public bool EvaluateEndElement ()
+ {
+ return State.EvaluateEndElement ();
+ }
- public void Clear ()
- {
- Element = null;
- SchemaType = null;
- SiblingState = null;
- // FIXME: It should be fine. Need more refactory.
-// ChildState = null;
- LocalTypeDefinition = null;
- }
+ public void SetElement (XsElement element)
+ {
+ Element = element;
+ }
+ }
- public void PushScope (int depth)
- {
- contextStack [depth] = this.MemberwiseClone ();
- }
+ internal class XsdIDManager
+ {
+ public XsdIDManager ()
+ {
+ }
+
+ Hashtable idList = new Hashtable ();
+ ArrayList missingIDReferences;
+ string thisElementId;
- public void PopScope (int depth)
- {
- Load (depth);
- contextStack.Remove (depth + 1);
+ private ArrayList MissingIDReferences {
+ get {
+ if (missingIDReferences == null)
+ missingIDReferences = new ArrayList ();
+ return missingIDReferences;
}
+ }
+
+ public void OnStartElement ()
+ {
+ thisElementId = null;
+ }
- public void Load (int depth)
- {
- Clear ();
- XsdValidationContext restored = (XsdValidationContext) contextStack [depth];
- if (restored != null) {
- this.Element = restored.Element;
- this.SiblingState = restored.SiblingState;
- this.SchemaType = restored.SchemaType;
- this.LocalTypeDefinition = restored.LocalTypeDefinition;
+ // 3.4.4-5 wild IDs
+ public string AssessEachAttributeIdentityConstraint (
+ XsDatatype dt, object parsedValue, string elementName)
+ {
+ // Validate identity constraints.
+ string str = parsedValue as string;
+ switch (dt.TokenizedType) {
+ case XmlTokenizedType.ID:
+ if (thisElementId != null)
+ return "ID type attribute was already assigned in the containing element.";
+ else
+ thisElementId = str;
+ if (idList.ContainsKey (str))
+ return "Duplicate ID value was found.";
+ else
+ idList.Add (str, elementName);
+ if (MissingIDReferences.Contains (str))
+ MissingIDReferences.Remove (str);
+ break;
+ case XmlTokenizedType.IDREF:
+ if (!idList.Contains (str))
+ MissingIDReferences.Add (str);
+ break;
+ case XmlTokenizedType.IDREFS:
+ string [] idrefs = (string []) parsedValue;
+ for (int i = 0; i < idrefs.Length; i++) {
+ string id = idrefs [i];
+ if (!idList.Contains (id))
+ MissingIDReferences.Add (id);
}
+ break;
}
+ return null;
+ }
+
+ public object FindID (string name)
+ {
+ return idList [name];
}
- }
+ public bool HasMissingIDReferences ()
+ {
+ return missingIDReferences != null
+ && missingIDReferences.Count > 0;
+ }
+
+ public string GetMissingIDString ()
+ {
+ return String.Join (" ",
+ MissingIDReferences.ToArray (typeof (string))
+ as string []);
+ }
+ }
}