Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/mono.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/mcs
diff options
context:
space:
mode:
authorAtsushi Eno <atsushieno@gmail.com>2004-12-14 15:09:23 +0300
committerAtsushi Eno <atsushieno@gmail.com>2004-12-14 15:09:23 +0300
commit2ff40096cb78bb837b9d1df6766433ae43b79cdc (patch)
tree662777b1a8a2a7fdfced98c50d6f4e5e8ffd5c7f /mcs
parent6e1bb0f3e948e7853bd8af0933d6d6137aaa07c2 (diff)
2004-12-14 Atsushi Enomoto <atsushi@ximian.com>
* System.Xml.dll.sources : added XmlSchemaValidatingReader. * XmlSchemaValidatingReader.cs : new file; another XmlReader implementation that handles XSD validation. It is an reference application for XmlSchemaValidator. * XsdValidatingReader.cs : Use readerLineInfo for IXmlLineInfo. * XmlReaderSettings.cs : XsdValidate and DtdValidate are now ValidationType. * XmlReader.cs : In Create(), use XmlSchemaValidatingReader for xsd validation. * XmlSchemaValidator.cs : implemented basic validation feature. svn path=/trunk/mcs/; revision=37739
Diffstat (limited to 'mcs')
-rw-r--r--mcs/class/System.XML/ChangeLog4
-rw-r--r--mcs/class/System.XML/Mono.Xml.Schema/ChangeLog7
-rwxr-xr-xmcs/class/System.XML/Mono.Xml.Schema/XmlSchemaValidatingReader.cs858
-rw-r--r--mcs/class/System.XML/Mono.Xml.Schema/XsdValidatingReader.cs17
-rwxr-xr-xmcs/class/System.XML/System.Xml.Schema/ChangeLog4
-rwxr-xr-xmcs/class/System.XML/System.Xml.Schema/XmlSchemaValidator.cs1190
-rwxr-xr-xmcs/class/System.XML/System.Xml.dll.sources1
-rw-r--r--mcs/class/System.XML/System.Xml/ChangeLog7
-rw-r--r--mcs/class/System.XML/System.Xml/XmlReader.cs21
-rwxr-xr-xmcs/class/System.XML/System.Xml/XmlReaderSettings.cs20
10 files changed, 2060 insertions, 69 deletions
diff --git a/mcs/class/System.XML/ChangeLog b/mcs/class/System.XML/ChangeLog
index 0f1047fe765..a76731e7676 100644
--- a/mcs/class/System.XML/ChangeLog
+++ b/mcs/class/System.XML/ChangeLog
@@ -1,3 +1,7 @@
+2004-12-14 Atsushi Enomoto <atsushi@ximian.com>
+
+ * System.Xml.dll.sources : added XmlSchemaValidatingReader.
+
2004-12-08 Atsushi Enomoto <atsushi@ximian.com>
* System.Xml.dll.sources : added XmlSchemaValidator.cs,
diff --git a/mcs/class/System.XML/Mono.Xml.Schema/ChangeLog b/mcs/class/System.XML/Mono.Xml.Schema/ChangeLog
index d52356ae9fb..7c740b94fc8 100644
--- a/mcs/class/System.XML/Mono.Xml.Schema/ChangeLog
+++ b/mcs/class/System.XML/Mono.Xml.Schema/ChangeLog
@@ -1,5 +1,12 @@
2004-12-14 Atsushi Enomoto <atsushi@ximian.com>
+ * XmlSchemaValidatingReader.cs : new file; another XmlReader
+ implementation that handles XSD validation. It is an reference
+ application for XmlSchemaValidator.
+ * XsdValidatingReader.cs : Use readerLineInfo for IXmlLineInfo.
+
+2004-12-14 Atsushi Enomoto <atsushi@ximian.com>
+
* XsdIdentityState.cs : use validation exception for 2.0.
ProcessMatch() does not have to return bool. Use break and continue
and reduced indentation.
diff --git a/mcs/class/System.XML/Mono.Xml.Schema/XmlSchemaValidatingReader.cs b/mcs/class/System.XML/Mono.Xml.Schema/XmlSchemaValidatingReader.cs
new file mode 100755
index 00000000000..9ff42dcf50e
--- /dev/null
+++ b/mcs/class/System.XML/Mono.Xml.Schema/XmlSchemaValidatingReader.cs
@@ -0,0 +1,858 @@
+//
+// XmlSchemaValidatingReader.cs
+//
+// Author:
+// Atsushi Enomoto <atsushi@ximian.com>
+//
+// (C)2004 Novell Inc,
+//
+
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+using System;
+using System.Collections;
+using System.Text;
+using System.Xml;
+using System.Xml.Schema;
+using System.Xml.XPath;
+using Mono.Xml;
+
+#if NET_2_0
+
+using QName = System.Xml.XmlQualifiedName;
+using Form = System.Xml.Schema.XmlSchemaForm;
+using Use = System.Xml.Schema.XmlSchemaUse;
+using ContentType = System.Xml.Schema.XmlSchemaContentType;
+using Validity = System.Xml.Schema.XmlSchemaValidity;
+using ValidationFlags = System.Xml.Schema.XmlSchemaValidationFlags;
+using SOMList = System.Xml.Schema.XmlSchemaObjectCollection;
+using SOMObject = System.Xml.Schema.XmlSchemaObject;
+using XsElement = System.Xml.Schema.XmlSchemaElement;
+using XsAttr = System.Xml.Schema.XmlSchemaAttribute;
+using AttrGroup = System.Xml.Schema.XmlSchemaAttributeGroup;
+using AttrGroupRef = System.Xml.Schema.XmlSchemaAttributeGroupRef;
+using XsDatatype = System.Xml.Schema.XmlSchemaDatatype;
+using SchemaType = System.Xml.Schema.XmlSchemaType;
+using SimpleType = System.Xml.Schema.XmlSchemaSimpleType;
+using ComplexType = System.Xml.Schema.XmlSchemaComplexType;
+using SimpleModel = System.Xml.Schema.XmlSchemaSimpleContent;
+using SimpleExt = System.Xml.Schema.XmlSchemaSimpleContentExtension;
+using SimpleRst = System.Xml.Schema.XmlSchemaSimpleContentRestriction;
+using ComplexModel = System.Xml.Schema.XmlSchemaComplexContent;
+using ComplexExt = System.Xml.Schema.XmlSchemaComplexContentExtension;
+using ComplexRst = System.Xml.Schema.XmlSchemaComplexContentRestriction;
+using SimpleTypeRst = System.Xml.Schema.XmlSchemaSimpleTypeRestriction;
+using SimpleList = System.Xml.Schema.XmlSchemaSimpleTypeList;
+using SimpleUnion = System.Xml.Schema.XmlSchemaSimpleTypeUnion;
+using SchemaFacet = System.Xml.Schema.XmlSchemaFacet;
+using LengthFacet = System.Xml.Schema.XmlSchemaLengthFacet;
+using MinLengthFacet = System.Xml.Schema.XmlSchemaMinLengthFacet;
+using Particle = System.Xml.Schema.XmlSchemaParticle;
+using Sequence = System.Xml.Schema.XmlSchemaSequence;
+using Choice = System.Xml.Schema.XmlSchemaChoice;
+using ValException = System.Xml.Schema.XmlSchemaValidationException;
+
+namespace Mono.Xml.Schema
+{
+ internal class XmlSchemaValidatingReader : XmlReader, IXmlLineInfo
+ {
+ static readonly XsAttr [] emptyAttributeArray =
+ new XsAttr [0];
+
+ #region Instance Fields
+
+ XmlReader reader;
+ XmlSchemaSet schemas;
+ XmlSchemaValidator v;
+ XmlValueGetter getter;
+ XmlSchemaInfo xsinfo;
+ IXmlLineInfo readerLineInfo;
+ ValidationType validationType;
+// IHasXmlSchemaInfo sourceReaderSchemaInfo;
+ int startDepth;
+
+ StringBuilder tmpBuilder = new StringBuilder ();
+
+ XsAttr [] defaultAttributes = emptyAttributeArray;
+ int currentDefaultAttribute = -1;
+ ArrayList defaultAttributesCache = new ArrayList ();
+ bool defaultAttributeConsumed;
+ object currentAttrType;
+
+ // Extra for XmlSchemaValidtingReader
+ // (not in XsdValidatingReader)
+ XsElement element; // ... xsinfo.Element?
+ object xsiType; // ... xsinfo.SchemaType?
+
+ #endregion
+
+ public XmlSchemaValidatingReader (XmlReader reader, XmlSchemaSet schemas)
+ {
+ IXmlNamespaceResolver nsResolver = reader as IXmlNamespaceResolver;
+ if (nsResolver == null)
+ throw new ArgumentException ("Argument XmlReader must implement IXmlNamespaceResolver.");
+
+ this.reader = reader;
+ if (schemas == null)
+ schemas = new XmlSchemaSet ();
+ this.schemas = schemas;
+ v = new XmlSchemaValidator (
+ reader.NameTable,
+ schemas,
+ nsResolver,
+ ValidationFlags.IgnoreValidationWarnings
+ | ValidationFlags.IgnoreSchemaLocation
+ | ValidationFlags.IgnoreInlineSchema);
+
+ readerLineInfo = reader as IXmlLineInfo;
+ startDepth = reader.Depth;
+ getter = delegate () { return Value; };
+ xsinfo = new XmlSchemaInfo (); // transition cache
+ v.LineInfoProvider = this;
+ v.ValidationEventSender = reader;
+#if !MS_NET
+ v.XmlResolver = schemas.XmlResolver;
+#endif
+ v.SourceUri = reader.BaseURI; // FIXME: it is in fact not in MS.NET.
+ v.Initialize ();
+ }
+
+ public XmlSchemaValidatingReader (XmlReader reader,
+ XmlReaderSettings settings)
+ {
+ IXmlNamespaceResolver nsResolver = reader as IXmlNamespaceResolver;
+ if (nsResolver == null)
+ throw new ArgumentException ("Argument XmlReader must implement IXmlNamespaceResolver.");
+
+ schemas = settings.Schemas;
+ if (schemas == null)
+ schemas = new XmlSchemaSet ();
+
+ this.reader = reader;
+ v = new XmlSchemaValidator (
+ reader.NameTable,
+ schemas,
+ nsResolver,
+ settings.ValidationFlags);
+
+ readerLineInfo = reader as IXmlLineInfo;
+ startDepth = reader.Depth;
+ getter = delegate () { return Value; };
+ v.LineInfoProvider = this;
+ v.ValidationEventSender = reader;
+#if !MS_NET
+ if (settings != null && settings.Schemas != null)
+ v.XmlResolver = settings.Schemas.XmlResolver;
+#endif
+ v.Initialize ();
+ }
+
+ public XmlSchemaValidatingReader (
+ XPathNavigator navigator,
+ XmlSchemaSet schemas,
+ ValidationEventHandler handler)
+ {
+ this.reader = navigator.ReadSubtree ();
+ startDepth = reader.Depth;
+ IXmlSchemaInfo info = navigator.SchemaInfo;
+ SchemaType schemaType = info != null ?
+ info.SchemaType : null;
+
+ if (schemas == null && schemaType == null)
+ throw new ArgumentException ("Neither of XmlSchemaSet is specified, nor XPathNavigator does not provide schema type information on current node.");
+
+ if (schemas == null)
+ schemas = new XmlSchemaSet (reader.NameTable);
+
+ v = new XmlSchemaValidator (
+ navigator.NameTable,
+ schemas,
+ navigator,
+ ValidationFlags.IgnoreSchemaLocation |
+ ValidationFlags.IgnoreInlineSchema);
+ this.schemas = schemas;
+
+ readerLineInfo = navigator as IXmlLineInfo;
+ getter = delegate () { return Value; };
+ v.LineInfoProvider = this;
+ v.ValidationEventSender = navigator;
+#if !MS_NET
+ v.XmlResolver = schemas.XmlResolver; // internal getter
+#endif
+ v.Initialize (schemaType);
+ }
+
+ public ValidationEventHandler ValidationEventHandler;
+
+ public object ActualType {
+ get {
+ return xsiType != null ?
+ xsiType :
+ element != null ? element.ElementType : null;
+ }
+ }
+
+ // clear default attributes, MoveTo*Attribute() transitent
+ // fields and so on.
+ private void ResetStateOnRead ()
+ {
+ currentDefaultAttribute = -1;
+ defaultAttributeConsumed = false;
+ currentAttrType = null;
+ defaultAttributes = emptyAttributeArray;
+ }
+
+ #region Properties
+
+ public int LineNumber {
+ get { return readerLineInfo != null ? readerLineInfo.LineNumber : 0; }
+ }
+
+ public int LinePosition {
+ get { return readerLineInfo != null ? readerLineInfo.LinePosition : 0; }
+ }
+
+ public XmlSchemaSet Schemas {
+ get { return schemas; }
+ }
+
+ public object SchemaType {
+ get {
+ if (ReadState != ReadState.Interactive)
+ return null;
+
+ switch (NodeType) {
+ case XmlNodeType.Element:
+ if (ActualType != null)
+ return ActualType;
+ else
+ return null;//SourceReaderSchemaType;
+ case XmlNodeType.Attribute:
+ if (currentAttrType == null) {
+ ComplexType ct = ActualType as ComplexType;
+ if (ct != null) {
+ XsAttr attdef = ct.AttributeUses [new XmlQualifiedName (LocalName, NamespaceURI)] as XsAttr;
+ if (attdef != null)
+ currentAttrType = attdef.AttributeType;
+ return currentAttrType;
+ }
+// currentAttrType = SourceReaderSchemaType;
+ }
+ return currentAttrType;
+ default:
+ return null;//SourceReaderSchemaType;
+ }
+ }
+ }
+
+ public ValidationType ValidationType {
+ get { return validationType; }
+ set {
+ if (ReadState != ReadState.Initial)
+ throw new InvalidOperationException ("ValidationType must be set before reading.");
+ validationType = value;
+ }
+ }
+
+ public IDictionary GetNamespacesInScope (XmlNamespaceScope scope)
+ {
+ IXmlNamespaceResolver resolver = reader as IXmlNamespaceResolver;
+ if (resolver == null)
+ throw new NotSupportedException ("The input XmlReader does not implement IXmlNamespaceResolver and thus this validating reader cannot collect in-scope namespaces.");
+ return resolver.GetNamespacesInScope (scope);
+ }
+
+ public string LookupPrefix (string ns)
+ {
+ return ((IXmlNamespaceResolver) this).LookupPrefix (ns, false);
+ }
+
+ public string LookupPrefix (string ns, bool atomizedNames)
+ {
+ IXmlNamespaceResolver resolver = reader as IXmlNamespaceResolver;
+ if (resolver == null)
+ throw new NotSupportedException ("The input XmlReader does not implement IXmlNamespaceResolver and thus this validating reader cannot execute namespace prefix lookup.");
+ return resolver.LookupPrefix (ns, atomizedNames);
+ }
+
+ // It is used only for independent XmlReader use, not for XmlValidatingReader.
+ public override object ReadTypedValue ()
+ {
+ return XmlSchemaUtil.ReadTypedValue (this, SchemaType, this as IXmlNamespaceResolver, tmpBuilder);
+ }
+
+ // Public Overriden Properties
+
+ public override int AttributeCount {
+ get {
+ return reader.AttributeCount + defaultAttributes.Length;
+ }
+ }
+
+ public override string BaseURI {
+ get { return reader.BaseURI; }
+ }
+
+ // If this class is used to implement XmlValidatingReader,
+ // it should be left to DTDValidatingReader. In other cases,
+ // it depends on the reader's ability.
+ public override bool CanResolveEntity {
+ get { return reader.CanResolveEntity; }
+ }
+
+ public override int Depth {
+ get {
+ if (currentDefaultAttribute < 0)
+ return reader.Depth;
+ if (this.defaultAttributeConsumed)
+ return reader.Depth + 2;
+ return reader.Depth + 1;
+ }
+ }
+
+ public override bool EOF {
+ get { return reader.EOF; }
+ }
+
+ public override bool HasValue {
+ get {
+ if (currentDefaultAttribute < 0)
+ return reader.HasValue;
+ return true;
+ }
+ }
+
+ public override bool IsDefault {
+ get {
+ if (currentDefaultAttribute < 0)
+ return reader.IsDefault;
+ return true;
+ }
+ }
+
+ public override bool IsEmptyElement {
+ get {
+ if (currentDefaultAttribute < 0)
+ return reader.IsEmptyElement;
+ return false;
+ }
+ }
+
+ public override string this [int i] {
+ get { return GetAttribute (i); }
+ }
+
+ public override string this [string name] {
+ get { return GetAttribute (name); }
+ }
+
+ public override string this [string localName, string ns] {
+ get { return GetAttribute (localName, ns); }
+ }
+
+ int IXmlLineInfo.LineNumber {
+ get { return readerLineInfo != null ? readerLineInfo.LineNumber : 0; }
+ }
+
+ int IXmlLineInfo.LinePosition {
+ get { return readerLineInfo != null ? readerLineInfo.LinePosition : 0; }
+ }
+
+ public override string LocalName {
+ get {
+ if (currentDefaultAttribute < 0)
+ return reader.LocalName;
+ if (defaultAttributeConsumed)
+ return String.Empty;
+ return defaultAttributes [currentDefaultAttribute].QualifiedName.Name;
+ }
+ }
+
+ public override string Name {
+ get {
+ if (currentDefaultAttribute < 0)
+ return reader.Name;
+ if (defaultAttributeConsumed)
+ return String.Empty;
+
+ XmlQualifiedName qname = defaultAttributes [currentDefaultAttribute].QualifiedName;
+ string prefix = Prefix;
+ if (prefix == String.Empty)
+ return qname.Name;
+ else
+ return String.Concat (prefix, ":", qname.Name);
+ }
+ }
+
+ public override string NamespaceURI {
+ get {
+ if (currentDefaultAttribute < 0)
+ return reader.NamespaceURI;
+ if (defaultAttributeConsumed)
+ return String.Empty;
+ return defaultAttributes [currentDefaultAttribute].QualifiedName.Namespace;
+ }
+ }
+
+ public override XmlNameTable NameTable {
+ get { return reader.NameTable; }
+ }
+
+ public override XmlNodeType NodeType {
+ get {
+ if (currentDefaultAttribute < 0)
+ return reader.NodeType;
+ if (defaultAttributeConsumed)
+ return XmlNodeType.Text;
+ return XmlNodeType.Attribute;
+ }
+ }
+
+ public XmlParserContext ParserContext {
+ get { return XmlSchemaUtil.GetParserContext (reader); }
+ }
+
+ public override string Prefix {
+ get {
+ if (currentDefaultAttribute < 0)
+ return reader.Prefix;
+ if (defaultAttributeConsumed)
+ return String.Empty;
+ XmlQualifiedName qname = defaultAttributes [currentDefaultAttribute].QualifiedName;
+ string prefix = this.ParserContext.NamespaceManager.LookupPrefix (qname.Namespace, false);
+ if (prefix == null)
+ return String.Empty;
+ else
+ return prefix;
+ }
+ }
+
+ public override char QuoteChar {
+ get { return reader.QuoteChar; }
+ }
+
+ public override ReadState ReadState {
+ get { return reader.ReadState; }
+ }
+
+ public override string Value {
+ get {
+ if (currentDefaultAttribute < 0)
+ return reader.Value;
+ string value = defaultAttributes [currentDefaultAttribute].ValidatedDefaultValue;
+ if (value == null)
+ value = defaultAttributes [currentDefaultAttribute].ValidatedFixedValue;
+ return value;
+ }
+ }
+
+ public override string XmlLang {
+ get {
+ string xmlLang = reader.XmlLang;
+ if (xmlLang != null)
+ return xmlLang;
+ int idx = this.FindDefaultAttribute ("lang", XmlNamespaceManager.XmlnsXml);
+ if (idx < 0)
+ return null;
+ xmlLang = defaultAttributes [idx].ValidatedDefaultValue;
+ if (xmlLang == null)
+ xmlLang = defaultAttributes [idx].ValidatedFixedValue;
+ return xmlLang;
+ }
+ }
+
+ public override XmlSpace XmlSpace {
+ get {
+ XmlSpace space = reader.XmlSpace;
+ if (space != XmlSpace.None)
+ return space;
+ int idx = this.FindDefaultAttribute ("space", XmlNamespaceManager.XmlnsXml);
+ if (idx < 0)
+ return XmlSpace.None;
+ string spaceSpec = defaultAttributes [idx].ValidatedDefaultValue;
+ if (spaceSpec == null)
+ spaceSpec = defaultAttributes [idx].ValidatedFixedValue;
+ return (XmlSpace) Enum.Parse (typeof (XmlSpace), spaceSpec, false);
+ }
+ }
+ #endregion
+
+ #region Public Methods
+
+ // Overrided Methods
+
+ public override void Close ()
+ {
+ reader.Close ();
+ }
+
+ public override string GetAttribute (int i)
+ {
+ switch (reader.NodeType) {
+ case XmlNodeType.XmlDeclaration:
+ case XmlNodeType.DocumentType:
+ return reader.GetAttribute (i);
+ }
+
+ if (reader.AttributeCount > i)
+ reader.GetAttribute (i);
+ int defIdx = i - reader.AttributeCount;
+ if (i < AttributeCount)
+ return defaultAttributes [defIdx].DefaultValue;
+
+ throw new ArgumentOutOfRangeException ("i", i, "Specified attribute index is out of range.");
+ }
+
+ public override string GetAttribute (string name)
+ {
+ switch (reader.NodeType) {
+ case XmlNodeType.XmlDeclaration:
+ case XmlNodeType.DocumentType:
+ return reader.GetAttribute (name);
+ }
+
+ string value = reader.GetAttribute (name);
+ if (value != null)
+ return value;
+
+ XmlQualifiedName qname = SplitQName (name);
+ return GetDefaultAttribute (qname.Name, qname.Namespace);
+ }
+
+ private XmlQualifiedName SplitQName (string name)
+ {
+ XmlConvert.VerifyName (name);
+
+ Exception ex = null;
+ XmlQualifiedName qname = XmlSchemaUtil.ToQName (reader, name, out ex);
+ if (ex != null)
+ return XmlQualifiedName.Empty;
+ else
+ return qname;
+ }
+
+ public override string GetAttribute (string localName, string ns)
+ {
+ switch (reader.NodeType) {
+ case XmlNodeType.XmlDeclaration:
+ case XmlNodeType.DocumentType:
+ return reader.GetAttribute (localName, ns);
+ }
+
+ string value = reader.GetAttribute (localName, ns);
+ if (value != null)
+ return value;
+
+ return GetDefaultAttribute (localName, ns);
+ }
+
+ private string GetDefaultAttribute (string localName, string ns)
+ {
+ int idx = this.FindDefaultAttribute (localName, ns);
+ if (idx < 0)
+ return null;
+ string value = defaultAttributes [idx].ValidatedDefaultValue;
+ if (value == null)
+ value = defaultAttributes [idx].ValidatedFixedValue;
+ return value;
+ }
+
+ private int FindDefaultAttribute (string localName, string ns)
+ {
+ for (int i = 0; i < this.defaultAttributes.Length; i++) {
+ XsAttr attr = defaultAttributes [i];
+ if (attr.QualifiedName.Name == localName &&
+ (ns == null || attr.QualifiedName.Namespace == ns))
+ return i;
+ }
+ return -1;
+ }
+
+ bool IXmlLineInfo.HasLineInfo ()
+ {
+ return readerLineInfo != null && readerLineInfo.HasLineInfo ();
+ }
+
+ public override string LookupNamespace (string prefix)
+ {
+ return reader.LookupNamespace (prefix);
+ }
+
+ public override string LookupNamespace (string prefix, bool atomizedNames)
+ {
+ IXmlNamespaceResolver res = reader as IXmlNamespaceResolver;
+ if (res != null)
+ return res.LookupNamespace (prefix, atomizedNames);
+ else
+ return reader.LookupNamespace (prefix);
+ }
+
+ public override void MoveToAttribute (int i)
+ {
+ switch (reader.NodeType) {
+ case XmlNodeType.XmlDeclaration:
+ case XmlNodeType.DocumentType:
+ reader.MoveToAttribute (i);
+ return;
+ }
+
+ currentAttrType = null;
+ if (i < reader.AttributeCount) {
+ reader.MoveToAttribute (i);
+ this.currentDefaultAttribute = -1;
+ this.defaultAttributeConsumed = false;
+ }
+
+ if (i < AttributeCount) {
+ this.currentDefaultAttribute = i - reader.AttributeCount;
+ this.defaultAttributeConsumed = false;
+ }
+ else
+ throw new ArgumentOutOfRangeException ("i", i, "Attribute index is out of range.");
+ }
+
+ public override bool MoveToAttribute (string name)
+ {
+ switch (reader.NodeType) {
+ case XmlNodeType.XmlDeclaration:
+ case XmlNodeType.DocumentType:
+ return reader.MoveToAttribute (name);
+ }
+
+ currentAttrType = null;
+ bool b = reader.MoveToAttribute (name);
+ if (b) {
+ this.currentDefaultAttribute = -1;
+ this.defaultAttributeConsumed = false;
+ return true;
+ }
+
+ return MoveToDefaultAttribute (name, null);
+ }
+
+ public override bool MoveToAttribute (string localName, string ns)
+ {
+ switch (reader.NodeType) {
+ case XmlNodeType.XmlDeclaration:
+ case XmlNodeType.DocumentType:
+ return reader.MoveToAttribute (localName, ns);
+ }
+
+ currentAttrType = null;
+ bool b = reader.MoveToAttribute (localName, ns);
+ if (b) {
+ this.currentDefaultAttribute = -1;
+ this.defaultAttributeConsumed = false;
+ return true;
+ }
+
+ return MoveToDefaultAttribute (localName, ns);
+ }
+
+ private bool MoveToDefaultAttribute (string localName, string ns)
+ {
+ int idx = this.FindDefaultAttribute (localName, ns);
+ if (idx < 0)
+ return false;
+ currentDefaultAttribute = idx;
+ defaultAttributeConsumed = false;
+ return true;
+ }
+
+ public override bool MoveToElement ()
+ {
+ currentDefaultAttribute = -1;
+ defaultAttributeConsumed = false;
+ currentAttrType = null;
+ return reader.MoveToElement ();
+ }
+
+ public override bool MoveToFirstAttribute ()
+ {
+ switch (reader.NodeType) {
+ case XmlNodeType.XmlDeclaration:
+ case XmlNodeType.DocumentType:
+ return reader.MoveToFirstAttribute ();
+ }
+
+ currentAttrType = null;
+ if (reader.AttributeCount > 0) {
+ bool b = reader.MoveToFirstAttribute ();
+ if (b) {
+ currentDefaultAttribute = -1;
+ defaultAttributeConsumed = false;
+ }
+ return b;
+ }
+
+ if (this.defaultAttributes.Length > 0) {
+ currentDefaultAttribute = 0;
+ defaultAttributeConsumed = false;
+ return true;
+ }
+ else
+ return false;
+ }
+
+ public override bool MoveToNextAttribute ()
+ {
+ switch (reader.NodeType) {
+ case XmlNodeType.XmlDeclaration:
+ case XmlNodeType.DocumentType:
+ return reader.MoveToNextAttribute ();
+ }
+
+ currentAttrType = null;
+ if (currentDefaultAttribute >= 0) {
+ if (defaultAttributes.Length == currentDefaultAttribute + 1)
+ return false;
+ currentDefaultAttribute++;
+ defaultAttributeConsumed = false;
+ return true;
+ }
+
+ bool b = reader.MoveToNextAttribute ();
+ if (b) {
+ currentDefaultAttribute = -1;
+ defaultAttributeConsumed = false;
+ return true;
+ }
+
+ if (defaultAttributes.Length > 0) {
+ currentDefaultAttribute = 0;
+ defaultAttributeConsumed = false;
+ return true;
+ }
+ else
+ return false;
+ }
+
+ public override bool Read ()
+ {
+ if (!reader.Read ()) {
+ v.EndValidation ();
+ return false;
+ }
+
+ ResetStateOnRead ();
+
+ switch (reader.NodeType) {
+ case XmlNodeType.Element:
+ // FIXME: find out what another overload means.
+ v.ValidateElement (reader.LocalName,
+ reader.NamespaceURI,
+ xsinfo);
+
+ if (reader.MoveToAttribute ("nil", XmlSchema.InstanceNamespace)) {
+ v.ValidateAttribute ("nil",
+ XmlSchema.InstanceNamespace,
+ getter, xsinfo);
+ reader.MoveToElement ();
+ }
+
+ if (reader.MoveToAttribute ("type", XmlSchema.InstanceNamespace)) {
+ v.ValidateAttribute ("type",
+ XmlSchema.InstanceNamespace,
+ getter, xsinfo);
+ reader.MoveToElement ();
+ }
+
+ if (reader.MoveToFirstAttribute ()) {
+ do {
+ if (reader.NamespaceURI == "http://www.w3.org/2000/xmlns/")
+ continue;
+ v.ValidateAttribute (
+ reader.LocalName,
+ reader.NamespaceURI,
+ getter,
+ xsinfo);
+ } while (reader.MoveToNextAttribute ());
+ reader.MoveToElement ();
+ }
+ v.ValidateEndOfAttributes ();
+ v.GetUnspecifiedDefaultAttributes (
+ defaultAttributesCache);
+ defaultAttributes = (XsAttr [])
+ defaultAttributesCache.ToArray (
+ typeof (XsAttr));
+
+ if (reader.IsEmptyElement)
+ goto case XmlNodeType.EndElement;
+ break;
+ case XmlNodeType.EndElement:
+ // FIXME: find out what another overload means.
+ v.ValidateEndElement (xsinfo);
+ break;
+ case XmlNodeType.Text:
+ v.ValidateText (getter);
+ break;
+ case XmlNodeType.SignificantWhitespace:
+ case XmlNodeType.Whitespace:
+ v.ValidateWhitespace (getter);
+ break;
+ }
+
+ return true;
+ }
+
+ public override bool ReadAttributeValue ()
+ {
+ if (currentDefaultAttribute < 0)
+ return reader.ReadAttributeValue ();
+
+ if (this.defaultAttributeConsumed)
+ return false;
+
+ defaultAttributeConsumed = true;
+ return true;
+ }
+
+#if NET_1_0
+ public override string ReadInnerXml ()
+ {
+ // MS.NET 1.0 has a serious bug here. It skips validation.
+ return ReadInnerXmlInternal ();
+ }
+
+ public override string ReadOuterXml ()
+ {
+ // MS.NET 1.0 has a serious bug here. It skips validation.
+ return ReadInnerXmlInternal ();
+ }
+
+ // XmlReader.ReadString() should call derived this.Read().
+ public override string ReadString ()
+ {
+ return ReadStringInternal ();
+ }
+#endif
+
+ // This class itself does not have this feature.
+ public override void ResolveEntity ()
+ {
+ reader.ResolveEntity ();
+ }
+
+ #endregion
+ }
+}
+
+#endif
diff --git a/mcs/class/System.XML/Mono.Xml.Schema/XsdValidatingReader.cs b/mcs/class/System.XML/Mono.Xml.Schema/XsdValidatingReader.cs
index 97f4a62c363..aa7c1443515 100644
--- a/mcs/class/System.XML/Mono.Xml.Schema/XsdValidatingReader.cs
+++ b/mcs/class/System.XML/Mono.Xml.Schema/XsdValidatingReader.cs
@@ -334,11 +334,11 @@ namespace Mono.Xml.Schema
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; }
}
@@ -826,11 +826,10 @@ namespace Mono.Xml.Schema
case ContentProc.Lax:
break;
default:
- // FIXME: why is it not invalid if xsi:type exists?
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;
}
}
@@ -1121,7 +1120,7 @@ namespace Mono.Xml.Schema
XsdKeyTable seq = (XsdKeyTable) keyTables [i];
if (seq.SelectorMatches (this.elementQNameStack, reader.Depth) != null) {
// creates and registers new entry.
- XsdKeyEntry entry = new XsdKeyEntry (seq, reader.Depth, reader as IXmlLineInfo);
+ XsdKeyEntry entry = new XsdKeyEntry (seq, reader.Depth, readerLineInfo);
seq.Entries.Add (entry);
}
}
@@ -1146,7 +1145,7 @@ namespace Mono.Xml.Schema
private void ProcessKeyEntry (XsdKeyEntry entry)
{
bool isNil = XsiNilDepth == Depth;
- entry.ProcessMatch (false, elementQNameStack, this, NameTable, BaseURI, SchemaType, ParserContext.NamespaceManager, this as IXmlLineInfo, Depth, null, null, null, isNil, CurrentKeyFieldConsumers);
+ entry.ProcessMatch (false, elementQNameStack, this, NameTable, BaseURI, SchemaType, ParserContext.NamespaceManager, readerLineInfo, Depth, null, null, null, isNil, CurrentKeyFieldConsumers);
if (MoveToFirstAttribute ()) {
try {
do {
@@ -1155,7 +1154,7 @@ namespace Mono.Xml.Schema
case XmlSchema.InstanceNamespace:
continue;
}
- entry.ProcessMatch (true, elementQNameStack, this, NameTable, BaseURI, SchemaType, ParserContext.NamespaceManager, this as IXmlLineInfo, Depth, LocalName, NamespaceURI, Value, false, CurrentKeyFieldConsumers);
+ entry.ProcessMatch (true, elementQNameStack, this, NameTable, BaseURI, SchemaType, ParserContext.NamespaceManager, readerLineInfo, Depth, LocalName, NamespaceURI, Value, false, CurrentKeyFieldConsumers);
} while (MoveToNextAttribute ());
} finally {
MoveToElement ();
@@ -1191,7 +1190,7 @@ namespace Mono.Xml.Schema
if (identity == null)
identity = value;
- if (!field.SetIdentityField (identity, reader.Depth == xsiNilDepth, dt as XsdAnySimpleType, this.Depth, (IXmlLineInfo) this))
+ 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);
}
@@ -1346,7 +1345,7 @@ namespace Mono.Xml.Schema
return -1;
}
- bool IXmlLineInfo.HasLineInfo ()
+ public bool HasLineInfo ()
{
return readerLineInfo != null && readerLineInfo.HasLineInfo ();
}
diff --git a/mcs/class/System.XML/System.Xml.Schema/ChangeLog b/mcs/class/System.XML/System.Xml.Schema/ChangeLog
index fa7f909fcff..e7405e9f8d0 100755
--- a/mcs/class/System.XML/System.Xml.Schema/ChangeLog
+++ b/mcs/class/System.XML/System.Xml.Schema/ChangeLog
@@ -1,5 +1,9 @@
2004-12-14 Atsushi Enomoto <atsushi@ximian.com>
+ * XmlSchemaValidator.cs : implemented basic validation feature.
+
+2004-12-14 Atsushi Enomoto <atsushi@ximian.com>
+
* XmlSchemaUtil.cs : added FindAttributeDeclaration() and
AttributeWildcardItemValid().
diff --git a/mcs/class/System.XML/System.Xml.Schema/XmlSchemaValidator.cs b/mcs/class/System.XML/System.Xml.Schema/XmlSchemaValidator.cs
index b7f6b67e6aa..3e4f0d7f7fe 100755
--- a/mcs/class/System.XML/System.Xml.Schema/XmlSchemaValidator.cs
+++ b/mcs/class/System.XML/System.Xml.Schema/XmlSchemaValidator.cs
@@ -7,6 +7,34 @@
// (C)2004 Novell Inc,
//
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+//
+// LAMESPEC:
+// - There is no assurance that xsi:type precedes to any other attributes,
+// or xsi:type is not handled.
+// - There is no SourceUri provision.
+//
+
#if NET_2_0
using System;
@@ -14,6 +42,7 @@ using System.Collections;
using System.IO;
using System.Text;
using System.Xml;
+using Mono.Xml.Schema;
using QName = System.Xml.XmlQualifiedName;
using Form = System.Xml.Schema.XmlSchemaForm;
@@ -21,12 +50,14 @@ using Use = System.Xml.Schema.XmlSchemaUse;
using ContentType = System.Xml.Schema.XmlSchemaContentType;
using Validity = System.Xml.Schema.XmlSchemaValidity;
using ValidationFlags = System.Xml.Schema.XmlSchemaValidationFlags;
+using ContentProc = System.Xml.Schema.XmlSchemaContentProcessing;
using SOMList = System.Xml.Schema.XmlSchemaObjectCollection;
using SOMObject = System.Xml.Schema.XmlSchemaObject;
-using Element = System.Xml.Schema.XmlSchemaElement;
-using Attr = System.Xml.Schema.XmlSchemaAttribute;
+using XsElement = System.Xml.Schema.XmlSchemaElement;
+using XsAttribute = System.Xml.Schema.XmlSchemaAttribute;
using AttrGroup = System.Xml.Schema.XmlSchemaAttributeGroup;
using AttrGroupRef = System.Xml.Schema.XmlSchemaAttributeGroupRef;
+using XsDatatype = System.Xml.Schema.XmlSchemaDatatype;
using SimpleType = System.Xml.Schema.XmlSchemaSimpleType;
using ComplexType = System.Xml.Schema.XmlSchemaComplexType;
using SimpleModel = System.Xml.Schema.XmlSchemaSimpleContent;
@@ -35,21 +66,32 @@ using SimpleRst = System.Xml.Schema.XmlSchemaSimpleContentRestriction;
using ComplexModel = System.Xml.Schema.XmlSchemaComplexContent;
using ComplexExt = System.Xml.Schema.XmlSchemaComplexContentExtension;
using ComplexRst = System.Xml.Schema.XmlSchemaComplexContentRestriction;
-using SimpleTypeRst = System.Xml.Schema.XmlSchemaSimpleTypeRestriction;
-using SimpleList = System.Xml.Schema.XmlSchemaSimpleTypeList;
-using SimpleUnion = System.Xml.Schema.XmlSchemaSimpleTypeUnion;
+using SimpleTypeRest = System.Xml.Schema.XmlSchemaSimpleTypeRestriction;
+using SimpleTypeList = System.Xml.Schema.XmlSchemaSimpleTypeList;
+using SimpleTypeUnion = System.Xml.Schema.XmlSchemaSimpleTypeUnion;
using SchemaFacet = System.Xml.Schema.XmlSchemaFacet;
using LengthFacet = System.Xml.Schema.XmlSchemaLengthFacet;
using MinLengthFacet = System.Xml.Schema.XmlSchemaMinLengthFacet;
using Particle = System.Xml.Schema.XmlSchemaParticle;
using Sequence = System.Xml.Schema.XmlSchemaSequence;
using Choice = System.Xml.Schema.XmlSchemaChoice;
+using ValException = System.Xml.Schema.XmlSchemaValidationException;
namespace System.Xml.Schema
{
public class XmlSchemaValidator
{
+ enum Transition {
+ None,
+ Content,
+ StartTag,
+ Finished
+ }
+
+ static readonly XsAttribute [] emptyAttributeArray =
+ new XsAttribute [0];
+
public XmlSchemaValidator (
XmlNameTable nameTable,
XmlSchemaSet schemas,
@@ -68,6 +110,7 @@ namespace System.Xml.Schema
object nominalEventSender;
IXmlLineInfo lineInfo;
IXmlNamespaceResolver nsResolver;
+ string sourceUri;
// These fields will be from XmlReaderSettings or
// XPathNavigator.CheckValidity(). BTW, I think we could
@@ -75,20 +118,47 @@ namespace System.Xml.Schema
// XsdValidatingReader.
XmlNameTable nameTable;
XmlSchemaSet schemas;
- XmlResolver xmlResolver;
+ XmlResolver xmlResolver = new XmlUrlResolver ();
// "partialValidationType". but not sure how it will be used.
SOMObject startType;
- // Below are maybe from XmlReaderSettings, but XPathNavigator
+ // It is perhaps from XmlReaderSettings, but XPathNavigator
// does not have it.
ValidationFlags options;
+ // Validation state
+ Transition transition;
+ XsdParticleStateManager state;
+
+ ArrayList occuredAtts = new ArrayList ();
+ XsAttribute [] defaultAttributes = emptyAttributeArray;
+ ArrayList defaultAttributesCache = new ArrayList ();
+
+#region ID Constraints
+ XsdIDManager idManager = new XsdIDManager ();
+#endregion
+
+#region Key Constraints
+ ArrayList keyTables = new ArrayList ();
+ ArrayList currentKeyFieldConsumers = new ArrayList ();
+ ArrayList tmpKeyrefPool;
+#endregion
+ ArrayList elementQNameStack = new ArrayList ();
+
+ StringBuilder storedCharacters = new StringBuilder ();
+ bool shouldValidateCharacters;
+
+ int depth;
+ int xsiNilDepth = -1;
+ int skipValidationDepth = -1;
+
SOMObject currentType;
+
#endregion
- #region Properties
+ #region Public properties
// Settable Properties
@@ -113,18 +183,46 @@ namespace System.Xml.Schema
[MonoTODO]
public string SourceUri {
- get { throw new NotImplementedException (); }
+ get { return sourceUri; }
+ // FIXME: actually there seems no setter, but then
+ // it will never make sense.
+ set { sourceUri = value; }
+ }
+ #endregion
+
+ #region Private properties
+
+ private XsdValidationContext Context {
+ get { return state.Context; }
+ }
+
+ private bool IgnoreWarnings {
+ get { return (options & ValidationFlags
+ .IgnoreValidationWarnings) != 0; }
+ }
+
+ private bool IgnoreIdentity {
+ get { return (options & ValidationFlags
+ .IgnoreIdentityConstraints) != 0; }
}
+
#endregion
- #region Methods
+ #region Public methods
// State Monitor
- [MonoTODO]
public XmlSchemaAttribute [] GetExpectedAttributes ()
{
- throw new NotImplementedException ();
+ ArrayList al = new ArrayList ();
+ ComplexType cType = Context.ActualType as ComplexType;
+ if (cType == null)
+ return emptyAttributeArray;
+ foreach (DictionaryEntry entry in cType.AttributeUses)
+ if (!occuredAtts.Contains ((QName) entry.Key))
+ al.Add (entry.Value);
+ return (XsAttribute [])
+ al.ToArray (typeof (XsAttribute));
}
[MonoTODO]
@@ -133,104 +231,1122 @@ namespace System.Xml.Schema
throw new NotImplementedException ();
}
- [MonoTODO]
+ [MonoTODO ("check return type")]
public void GetUnspecifiedDefaultAttributes (ArrayList list)
{
- throw new NotImplementedException ();
+ list.AddRange (defaultAttributes);
}
- [MonoTODO]
public object FindID (string name)
{
- throw new NotImplementedException ();
+ // It looks returning the element's local name (string)
+ return idManager.FindID (name);
}
// State Controller
- public void Init ()
+ public void Initialize ()
{
- Init (null);
+ Initialize (null);
}
- public void Init (SOMObject startType)
+ [MonoTODO]
+ public void Initialize (SOMObject startType)
{
this.startType = startType;
+ transition = Transition.Content;
+ state = new XsdParticleStateManager ();
+ if (!schemas.IsCompiled)
+ schemas.Compile ();
}
// It must be called at the end of the validation (to check
// identity constraints etc.).
- [MonoTODO]
public void EndValidation ()
{
- throw new NotImplementedException ();
+ CheckState (Transition.Content);
+ transition = Transition.Finished;
+
+ if (schemas.Count == 0)
+ return;
+
+ if (depth > 0)
+ throw new InvalidOperationException (String.Format ("There are {0} open element(s). ValidateEndElement() must be called for each open element.", depth));
+
+ // 3.3.4 ElementLocallyValidElement 7 = Root Valid.
+ if (!IgnoreIdentity &&
+ idManager.HasMissingIDReferences ())
+ HandleError ("There are missing ID references: " + idManager.GetMissingIDString ());
}
+ // I guess it is for validation error recovery
[MonoTODO]
public void SkipToEndElement (XmlSchemaInfo info)
{
+ CheckState (Transition.Content);
+ if (schemas.Count == 0)
+ return;
throw new NotImplementedException ();
}
// I guess this weird XmlValueGetter is for such case that
// value might not be required (and thus it improves
- // performance in some cases. Doh.
+ // performance in some cases. Doh).
+ // The return value is typed primitive, is possible.
// AttDeriv
- [MonoTODO]
public object ValidateAttribute (
string localName,
string ns,
XmlValueGetter attributeValue,
XmlSchemaInfo info)
{
- throw new NotImplementedException ();
+ CheckState (Transition.StartTag);
+ if (ns == XmlNamespaceManager.XmlnsXmlns)
+ return null;
+ if (ns == XmlSchema.InstanceNamespace) {
+ switch (localName) {
+ case "schemaLocation":
+ HandleSchemaLocation (attributeValue ());
+ break;
+ case "noNamespaceSchemaLocation":
+ HandleNoNSSchemaLocation (attributeValue ());
+ break;
+ case "nil":
+ HandleXsiNil (attributeValue, info);
+ break;
+ case "type":
+ string xsiTypeName = attributeValue ();
+ HandleXsiType (xsiTypeName.Trim (XmlChar.WhitespaceChars));
+ break;
+ default:
+ HandleError ("Unknown schema instance namespace attribute: " + localName);
+ break;
+ }
+ return null; // no further validation.
+ }
+
+ if (schemas.Count == 0)
+ return null;
+
+ occuredAtts.Add (new QName (localName, ns));
+
+ // 3.3.4 Element Locally Valid (Type) - attribute
+ if (Context.ActualType is ComplexType)
+ return AssessAttributeElementLocallyValidType (localName, ns, attributeValue, info);
+ else
+ HandleError ("Current simple type cannot accept attributes other than schema instance namespace.");
+ return null;
}
// StartTagOpenDeriv
- [MonoTODO]
public void ValidateElement (
string localName,
string ns,
XmlSchemaInfo info) // How is it used?
{
- throw new NotImplementedException ();
+ CheckState (Transition.Content);
+ transition = Transition.StartTag;
+ if (schemas.Count == 0)
+ return;
+
+#region ID Constraints
+ if (!IgnoreIdentity)
+ idManager.OnStartElement ();
+#endregion
+ defaultAttributes = emptyAttributeArray;
+
+ elementQNameStack.Add (new XmlQualifiedName (localName, ns));
+
+ // If there is no schema information, then no validation is performed.
+ if (skipValidationDepth < 0 || depth <= skipValidationDepth) {
+ if (shouldValidateCharacters)
+ ValidateEndSimpleContent ();
+
+ AssessOpenStartElementSchemaValidity (localName, ns);
+ }
+
+ shouldValidateCharacters = true;
}
- [MonoTODO]
- public object ValidateEndElement (XmlSchemaInfo scheaInfo)
+ public object ValidateEndElement (XmlSchemaInfo schemaInfo)
{
- throw new NotImplementedException ();
+ return ValidateEndElement (schemaInfo, null);
}
- [MonoTODO]
- public object ValidateEndElement (XmlSchemaInfo scheaInfo,
+ // The return value is typed primitive, is supplied.
+ // EndTagDeriv
+ [MonoTODO ("Find out what 'var' parameter means.")]
+ public object ValidateEndElement (XmlSchemaInfo schemaInfo,
object var)
{
- throw new NotImplementedException ();
+ CheckState (Transition.Content);
+ if (schemas.Count == 0)
+ return null;
+ if (depth == 0)
+ throw new InvalidOperationException ("There was no corresponding call to 'ValidateElement' method.");
+
+ depth--;
+
+ object ret = null;
+ if (depth == skipValidationDepth)
+ skipValidationDepth = -1;
+ else if (skipValidationDepth < 0 || depth <= skipValidationDepth)
+ ret = AssessEndElementSchemaValidity ();
+
+ elementQNameStack.RemoveAt (elementQNameStack.Count - 1);
+
+ return ret;
}
// StartTagCloseDeriv
- [MonoTODO]
public void ValidateEndOfAttributes ()
{
- throw new NotImplementedException ();
+ CheckState (Transition.StartTag);
+ transition = Transition.Content;
+ if (schemas.Count == 0)
+ return;
+
+ AssessCloseStartElementSchemaValidity ();
}
// TextDeriv ... without text. Maybe typed check is done by
// ValidateAtomicValue().
- [MonoTODO]
public void ValidateText (XmlValueGetter getter)
{
- throw new NotImplementedException ();
+ CheckState (Transition.Content);
+ if (schemas.Count == 0)
+ return;
+
+ ComplexType ct = Context.ActualType as ComplexType;
+ if (ct != null && storedCharacters.Length > 0) {
+ switch (ct.ContentType) {
+ case XmlSchemaContentType.ElementOnly:
+ case XmlSchemaContentType.Empty:
+ HandleError ("Not allowed character content was found.");
+ break;
+ }
+ }
+
+ ValidateCharacters (getter);
}
+ // TextDeriv...?
[MonoTODO]
public void ValidateWhitespace (XmlValueGetter getter)
{
- throw new NotImplementedException ();
+ CheckState (Transition.Content);
+ if (schemas.Count == 0)
+ return;
+
+// throw new NotImplementedException ();
+ }
+
+ #endregion
+
+ #region Error handling
+
+ private void HandleError (string message)
+ {
+ HandleError (message, null, false);
+ }
+
+ private void HandleError (
+ string message, Exception innerException)
+ {
+ HandleError (message, innerException, false);
+ }
+
+ private void HandleError (string message,
+ Exception innerException, bool isWarning)
+ {
+ if (isWarning && IgnoreWarnings)
+ return;
+
+ ValException vex = new ValException (
+ message, nominalEventSender, SourceUri,
+ null, innerException);
+ HandleError (vex, isWarning);
+ }
+
+ private void HandleError (ValException exception)
+ {
+ HandleError (exception, false);
+ }
+
+ private void HandleError (ValException exception, bool isWarning)
+ {
+ if (isWarning && IgnoreWarnings)
+ return;
+
+ if (ValidationEventHandler == null)
+ throw exception;
+
+ ValidationEventArgs e = new ValidationEventArgs (
+ exception,
+ exception.Message,
+ isWarning ? XmlSeverityType.Warning :
+ XmlSeverityType.Error);
+ ValidationEventHandler (nominalEventSender, e);
+ }
+
+ #endregion
+
+ #region External schema resolution
+
+ private XmlSchema ReadExternalSchema (string uri)
+ {
+ Uri absUri = xmlResolver.ResolveUri ((SourceUri != "" ? new Uri (SourceUri) : null), uri);
+ XmlTextReader xtr = null;
+ try {
+ xtr = new XmlTextReader (absUri.ToString (),
+ (Stream) xmlResolver.GetEntity (
+ absUri, null, typeof (Stream)),
+ nameTable);
+ return XmlSchema.Read (
+ xtr, ValidationEventHandler);
+ } finally {
+ if (xtr != null)
+ xtr.Close ();
+ }
+ }
+
+ private void HandleSchemaLocation (string schemaLocation)
+ {
+ if (xmlResolver == null)
+ return;
+ XmlSchema schema = null;
+
+ bool schemaAdded = false;
+ string [] tmp = null;
+ try {
+ schemaLocation = XsDatatype.FromName ("token", XmlSchema.Namespace).Normalize (schemaLocation);
+ tmp = schemaLocation.Split (XmlChar.WhitespaceChars);
+ } catch (Exception ex) {
+ HandleError ("Invalid schemaLocation attribute format.", ex, true);
+ tmp = new string [0];
+ }
+ if (tmp.Length % 2 != 0)
+ HandleError ("Invalid schemaLocation attribute format.");
+ for (int i = 0; i < tmp.Length; i += 2) {
+ try {
+ schema = ReadExternalSchema (tmp [i + 1]);
+ } catch (Exception) { // FIXME: (wishlist) It is bad manner ;-(
+ HandleError ("Could not resolve schema location URI: " + schemaLocation, null, true);
+ continue;
+ }
+ if (schema.TargetNamespace == null)
+ schema.TargetNamespace = tmp [i];
+ else if (schema.TargetNamespace != tmp [i])
+ HandleError ("Specified schema has different target namespace.");
+
+ if (schema != null) {
+ if (!schemas.Contains (schema.TargetNamespace)) {
+ schemaAdded = true;
+ schemas.Add (schema);
+ }
+ }
+ }
+ // FIXME: should call Reprocess()?
+ if (schemaAdded)
+ schemas.Compile ();
+ }
+
+ private void HandleNoNSSchemaLocation (string noNsSchemaLocation)
+ {
+ if (xmlResolver == null)
+ return;
+ XmlSchema schema = null;
+ bool schemaAdded = false;
+
+ Uri absUri = null;
+ XmlTextReader xtr = null;
+ try {
+ schema = ReadExternalSchema (noNsSchemaLocation);
+ } catch (Exception) { // FIXME: (wishlist) It is bad manner ;-(
+ HandleError ("Could not resolve schema location URI: " + noNsSchemaLocation, null, true);
+ } finally {
+ if (xtr != null)
+ xtr.Close ();
+ }
+ if (schema != null && schema.TargetNamespace != null)
+ HandleError ("Specified schema has different target namespace.");
+
+ if (schema != null) {
+ if (!schemas.Contains (schema.TargetNamespace)) {
+ schemaAdded = true;
+ schemas.Add (schema);
+ }
+ }
+ // FIXME: should call Reprocess()?
+ if (schemaAdded)
+ schemas.Compile ();
+ }
+
+ #endregion
+
+ private void CheckState (Transition expected)
+ {
+ if (transition != expected) {
+ if (transition == Transition.None)
+ throw new InvalidOperationException ("Initialize() must be called before processing validation.");
+ else
+ throw new InvalidOperationException (
+ String.Format ("Unexpected attempt to validation state transition from {0} to {1} was happened.",
+ transition,
+ expected));
+ }
+ }
+
+ private XsElement FindElement (string name, string ns)
+ {
+ return (XsElement) schemas.GlobalElements [new XmlQualifiedName (name, ns)];
+ }
+
+ private XmlSchemaType FindType (XmlQualifiedName qname)
+ {
+ return (XmlSchemaType) schemas.GlobalTypes [qname];
+ }
+
+ #region Type Validation
+
+ private void ValidateStartElementParticle (
+ string localName, string ns)
+ {
+ if (Context.State == null)
+ return;
+ Context.XsiType = null;
+ state.CurrentElement = null;
+ Context.EvaluateStartElement (localName,
+ ns);
+ if (Context.IsInvalid)
+ HandleError ("Invalid start element: " + ns + ":" + localName);
+
+ Context.SetElement (state.CurrentElement);
+ }
+
+ private void AssessOpenStartElementSchemaValidity (
+ string localName, string ns)
+ {
+ // If the reader is inside xsi:nil (and failed
+ // on validation), then simply skip its content.
+ if (xsiNilDepth >= 0 && xsiNilDepth < depth)
+ HandleError ("Element item appeared, while current element context is nil.");
+
+ ValidateStartElementParticle (localName, ns);
+
+ // Create Validation Root, if not exist.
+ // [Schema Validity Assessment (Element) 1.1]
+ if (Context.Element == null) {
+ state.CurrentElement = FindElement (localName, ns);
+ Context.SetElement (state.CurrentElement);
+ }
+
+#region Key Constraints
+ if (!IgnoreIdentity)
+ ValidateKeySelectors ();
+ ValidateKeyFields (false, xsiNilDepth == depth,
+ Context.ActualType, null, null, null);
+#endregion
+ }
+
+ private void AssessCloseStartElementSchemaValidity ()
+ {
+ if (Context.XsiType != null)
+ AssessCloseStartElementLocallyValidType ();
+ else if (Context.Element != null) {
+ // element locally valid is checked only when
+ // xsi:type does not exist.
+ AssessElementLocallyValidElement ();
+ if (Context.Element.ElementType != null)
+ AssessCloseStartElementLocallyValidType ();
+ }
+
+ if (Context.Element == null) {
+ switch (state.ProcessContents) {
+ case ContentProc.Skip:
+ break;
+ case ContentProc.Lax:
+ break;
+ default:
+ QName current = (QName) elementQNameStack [elementQNameStack.Count - 1];
+ if (Context.XsiType == null &&
+ (schemas.Contains (current.Namespace) ||
+ !schemas.MissedSubComponents (current.Namespace)))
+ HandleError ("Element declaration for " + current + " is missing.");
+ break;
+ }
+ }
+
+ // Proceed to the next depth.
+
+ state.PushContext ();
+
+ XsdValidationState next = null;
+ if (state.ProcessContents == ContentProc.Skip)
+ skipValidationDepth = depth;
+ else {
+ // create child particle state.
+ ComplexType xsComplexType = Context.ActualType as ComplexType;
+ if (xsComplexType != null)
+ next = state.Create (xsComplexType.ValidatableParticle);
+ else if (state.ProcessContents == ContentProc.Lax)
+ next = state.Create (XmlSchemaAny.AnyTypeContent);
+ else
+ next = state.Create (XmlSchemaParticle.Empty);
+ }
+ Context.State = next;
+
+ depth++;
+ }
+
+ // It must be invoked after xsi:nil turned out not to be in
+ // this element.
+ private void AssessElementLocallyValidElement ()
+ {
+ XsElement element = Context.Element;
+ XmlQualifiedName qname = (XmlQualifiedName) elementQNameStack [elementQNameStack.Count - 1];
+ // 1.
+ if (element == null)
+ HandleError ("Element declaration is required for " + qname);
+ // 2.
+ if (element.ActualIsAbstract)
+ HandleError ("Abstract element declaration was specified for " + qname);
+ // 3. is checked inside ValidateAttribute().
+ }
+
+ // 3.3.4 Element Locally Valid (Type)
+ private void AssessCloseStartElementLocallyValidType ()
+ {
+ object schemaType = Context.ActualType;
+ if (schemaType == null) { // 1.
+ HandleError ("Schema type does not exist.");
+ return;
+ }
+ ComplexType cType = schemaType as ComplexType;
+ SimpleType sType = schemaType as SimpleType;
+ if (sType != null) {
+ // 3.1.1.
+ // Attributes are checked in ValidateAttribute().
+ } else if (cType != null) {
+ // 3.2. Also, 2. is checked there.
+ AssessCloseStartElementLocallyValidComplexType (cType);
+ }
+ }
+
+ // 3.4.4 Element Locally Valid (Complex Type)
+ private void AssessCloseStartElementLocallyValidComplexType (ComplexType cType)
+ {
+ // 1.
+ if (cType.IsAbstract) {
+ HandleError ("Target complex type is abstract.");
+ return;
+ }
+
+ // 2 (xsi:nil and content prohibition)
+ // See AssessStartElementSchemaValidity() and ValidateCharacters()
+ // 3. attribute uses and 5. wild IDs are handled at
+ // ValidateAttribute().
+
+ // Collect default attributes.
+ // 4.
+ foreach (XsAttribute attr in GetExpectedAttributes ()) {
+ if (attr.ValidatedUse == XmlSchemaUse.Required &&
+ attr.ValidatedFixedValue == null)
+ HandleError ("Required attribute " + attr.QualifiedName + " was not found.");
+ else if (attr.ValidatedDefaultValue != null || attr.ValidatedFixedValue != null)
+ defaultAttributesCache.Add (attr);
+ }
+ if (defaultAttributesCache.Count == 0)
+ defaultAttributes = emptyAttributeArray;
+ else
+ defaultAttributes = (XsAttribute [])
+ defaultAttributesCache.ToArray (
+ typeof (XsAttribute));
+ defaultAttributesCache.Clear ();
+ // 5. wild IDs was already checked at ValidateAttribute().
+
+ occuredAtts.Clear ();
+ }
+
+ private object AssessAttributeElementLocallyValidType (string localName, string ns, XmlValueGetter getter, XmlSchemaInfo info)
+ {
+ ComplexType cType = Context.ActualType as ComplexType;
+ XmlQualifiedName qname = new XmlQualifiedName (localName, ns);
+ // including 3.10.4 Item Valid (Wildcard)
+ XmlSchemaObject attMatch = XmlSchemaUtil.FindAttributeDeclaration (ns, schemas, cType, qname);
+ if (attMatch == null)
+ HandleError ("Attribute declaration was not found for " + qname);
+ XsAttribute attdecl = attMatch as XsAttribute;
+ if (attdecl != null) {
+ AssessAttributeLocallyValidUse (attdecl);
+ return AssessAttributeLocallyValid (attdecl, getter);
+ } // otherwise anyAttribute or null.
+ return null;
+ }
+
+ // 3.2.4 Attribute Locally Valid and 3.4.4
+ private object AssessAttributeLocallyValid (XsAttribute attr, XmlValueGetter getter)
+ {
+ // 2. - 4.
+ if (attr.AttributeType == null)
+ HandleError ("Attribute type is missing for " + attr.QualifiedName);
+ XsDatatype dt = attr.AttributeType as XsDatatype;
+ if (dt == null)
+ dt = ((SimpleType) attr.AttributeType).Datatype;
+ // It is a bit heavy process, so let's omit as long as possible ;-)
+ if (dt != SimpleType.AnySimpleType || attr.ValidatedFixedValue != null) {
+ string normalized = dt.Normalize (getter ());
+ object parsedValue = null;
+ try {
+ parsedValue = dt.ParseValue (normalized, nameTable, nsResolver);
+ } catch (Exception ex) { // FIXME: (wishlist) It is bad manner ;-(
+ HandleError ("Attribute value is invalid against its data type " + dt.TokenizedType, ex);
+ }
+ if (attr.ValidatedFixedValue != null && attr.ValidatedFixedValue != normalized) {
+ HandleError ("The value of the attribute " + attr.QualifiedName + " does not match with its fixed value.");
+ parsedValue = dt.ParseValue (attr.ValidatedFixedValue, nameTable, nsResolver);
+ }
+#region ID Constraints
+ if (!IgnoreIdentity) {
+ string error = idManager.AssessEachAttributeIdentityConstraint (dt, parsedValue, ((QName) elementQNameStack [elementQNameStack.Count - 1]).Name);
+ if (error != null)
+ HandleError (error);
+ }
+#endregion
+
+ #region Key Constraints
+ if (!IgnoreIdentity)
+ ValidateKeyFields (
+ true,
+ false,
+ attr.AttributeType,
+ attr.QualifiedName.Name,
+ attr.QualifiedName.Namespace,
+ getter);
+ #endregion
+
+ return parsedValue;
+ }
+ return null;
+ }
+
+ private void AssessAttributeLocallyValidUse (XsAttribute attr)
+ {
+ // This is extra check than spec 3.5.4
+ if (attr.ValidatedUse == XmlSchemaUse.Prohibited)
+ HandleError ("Attribute " + attr.QualifiedName + " is prohibited in this context.");
+ }
+
+ private object AssessEndElementSchemaValidity ()
+ {
+ ValidateEndElementParticle (); // validate against childrens' state.
+
+ object ret = ValidateEndSimpleContent ();
+
+ // 3.3.4 Assess ElementLocallyValidElement 5: value constraints.
+ // 3.3.4 Assess ElementLocallyValidType 3.1.3. = StringValid(3.14.4)
+ // => ValidateEndSimpleContent ().
+
+#region Key Constraints
+ if (!IgnoreIdentity)
+ ValidateEndElementKeyConstraints ();
+#endregion
+
+ // Reset xsi:nil, if required.
+ if (xsiNilDepth == depth)
+ xsiNilDepth = -1;
+ return ret;
+ }
+
+ private void ValidateEndElementParticle ()
+ {
+ if (Context.State != null) {
+ if (!Context.EvaluateEndElement ()) {
+ HandleError ("Invalid end element. There are still required content items.");
+ }
+ }
+ state.PopContext ();
+ }
+
+ // Utility for missing validation completion related to child items.
+ private void ValidateCharacters (XmlValueGetter getter)
+ {
+ if (xsiNilDepth >= 0 && xsiNilDepth < depth)
+ HandleError ("Element item appeared, while current element context is nil.");
+
+ if (shouldValidateCharacters)
+ storedCharacters.Append (getter ());
+ }
+
+
+ // Utility for missing validation completion related to child items.
+ private object ValidateEndSimpleContent ()
+ {
+ object ret = null;
+ if (shouldValidateCharacters)
+ ret = ValidateEndSimpleContentCore ();
+ shouldValidateCharacters = false;
+ storedCharacters.Length = 0;
+ return ret;
+ }
+
+ private object ValidateEndSimpleContentCore ()
+ {
+ if (Context.ActualType == null)
+ return null;
+
+ string value = storedCharacters.ToString ();
+ object ret = null;
+
+ 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;
+ }
+ }
+
+ XsDatatype dt = Context.ActualType as XsDatatype;
+ SimpleType st = Context.ActualType as SimpleType;
+ if (dt == null) {
+ if (st != null) {
+ dt = st.Datatype;
+ } else {
+ ComplexType ct = Context.ActualType as ComplexType;
+ dt = ct.Datatype;
+ switch (ct.ContentType) {
+ case XmlSchemaContentType.ElementOnly:
+ case XmlSchemaContentType.Empty:
+ 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)
+ HandleError ("Fixed value constraint was not satisfied.");
+ ret = AssessStringValid (st, dt, value);
+ }
+
+#region Key Constraints
+ if (!IgnoreIdentity)
+ ValidateSimpleContentIdentity (dt, value);
+#endregion
+
+ shouldValidateCharacters = false;
+ return ret;
+ }
+
+ // 3.14.4 String Valid
+ private object AssessStringValid (SimpleType st,
+ XsDatatype dt, string value)
+ {
+ XsDatatype validatedDatatype = dt;
+ object ret = null;
+ if (st != null) {
+ string normalized = validatedDatatype.Normalize (value);
+ string [] values;
+ XsDatatype itemDatatype;
+ SimpleType itemSimpleType;
+ switch (st.DerivedBy) {
+ case XmlSchemaDerivationMethod.List:
+ SimpleTypeList listContent = st.Content as SimpleTypeList;
+ values = normalized.Split (XmlChar.WhitespaceChars);
+ // LAMESPEC: Types of each element in
+ // the returned list might be
+ // inconsistent, so basically returning
+ // value does not make sense without
+ // explicit runtime type information
+ // for base primitive type.
+ object [] retValues = new object [values.Length];
+ 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)
+ continue;
+ // validate against ValidatedItemType
+ if (itemDatatype != null) {
+ try {
+ retValues [vi] = itemDatatype.ParseValue (each, nameTable, nsResolver);
+ } catch (Exception ex) { // FIXME: (wishlist) better exception handling ;-(
+ HandleError ("List type value contains one or more invalid values.", ex);
+ break;
+ }
+ }
+ else
+ AssessStringValid (itemSimpleType, itemSimpleType.Datatype, each);
+ }
+ ret = retValues;
+ break;
+ case XmlSchemaDerivationMethod.Union:
+ SimpleTypeUnion union = st.Content as SimpleTypeUnion;
+ {
+ string each = normalized;
+ // validate against ValidatedItemType
+ bool passed = false;
+ foreach (object eachType in union.ValidatedTypes) {
+ itemDatatype = eachType as XsDatatype;
+ itemSimpleType = eachType as SimpleType;
+ if (itemDatatype != null) {
+ try {
+ ret = itemDatatype.ParseValue (each, nameTable, nsResolver);
+ } catch (Exception) { // FIXME: (wishlist) better exception handling ;-(
+ continue;
+ }
+ }
+ else {
+ try {
+ ret = AssessStringValid (itemSimpleType, itemSimpleType.Datatype, each);
+ } catch (ValException) {
+ continue;
+ }
+ }
+ passed = true;
+ break;
+ }
+ if (!passed) {
+ HandleError ("Union type value contains one or more invalid values.");
+ break;
+ }
+ }
+ break;
+ case XmlSchemaDerivationMethod.Restriction:
+ SimpleTypeRest str = st.Content as SimpleTypeRest;
+ // facet validation
+ if (str != null) {
+ /* Don't forget to validate against inherited type's facets
+ * Could we simplify this by assuming that the basetype will also
+ * be restriction?
+ * */
+ // mmm, will check later.
+ SimpleType baseType = st.BaseXmlSchemaType as SimpleType;
+ if (baseType != null) {
+ ret = AssessStringValid (baseType, dt, normalized);
+ }
+ if (!str.ValidateValueWithFacets (normalized, nameTable)) {
+ HandleError ("Specified value was invalid against the facets.");
+ break;
+ }
+ }
+ validatedDatatype = st.Datatype;
+ break;
+ }
+ }
+ if (validatedDatatype != null) {
+ try {
+ ret = validatedDatatype.ParseValue (value, nameTable, nsResolver);
+ } catch (Exception ex) { // FIXME: (wishlist) It is bad manner ;-(
+ HandleError (String.Format ("Invalidly typed data was specified."), ex);
+ }
+ }
+ return ret;
+ }
+
+ #endregion
+
+ #region Key Constraints Validation
+ private XsdKeyTable CreateNewKeyTable (XmlSchemaIdentityConstraint ident)
+ {
+ XsdKeyTable seq = new XsdKeyTable (ident);
+ seq.StartDepth = depth;
+ this.keyTables.Add (seq);
+ return seq;
+ }
+
+ // 3.11.4 Identity Constraint Satisfied
+ private void ValidateKeySelectors ()
+ {
+ if (tmpKeyrefPool != null)
+ tmpKeyrefPool.Clear ();
+ 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];
+ XsdKeyTable seq = CreateNewKeyTable (ident);
+ if (ident is XmlSchemaKeyref) {
+ if (tmpKeyrefPool == null)
+ tmpKeyrefPool = new ArrayList ();
+ tmpKeyrefPool.Add (seq);
+ }
+ }
+ }
+
+ // (b) Evaluate current key sequences.
+ for (int i = 0; i < keyTables.Count; i++) {
+ XsdKeyTable seq = (XsdKeyTable) keyTables [i];
+ if (seq.SelectorMatches (this.elementQNameStack, depth) != null) {
+ // creates and registers new entry.
+ XsdKeyEntry entry = new XsdKeyEntry (seq, depth, lineInfo);
+ seq.Entries.Add (entry);
+ }
+ }
+ }
+
+ private void ValidateKeyFields (bool isAttr, bool isNil, object schemaType, string attrName, string attrNs, XmlValueGetter getter)
+ {
+ // (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++) {
+ try {
+ seq.Entries [j].ProcessMatch (
+ isAttr,
+ elementQNameStack,
+ nominalEventSender,
+ nameTable,
+ SourceUri,
+ schemaType,
+ nsResolver,
+ lineInfo,
+ depth,
+ attrName,
+ attrNs,
+ getter == null ?
+ null :
+ getter (),
+ isNil,
+ currentKeyFieldConsumers);
+ } catch (ValException ex) {
+ HandleError (ex);
+ }
+ }
+ }
+ }
+
+ private void ProcessKeyEntryOne (XsdKeyEntry entry, bool isAttr, bool isNil, object schemaType, string attrName, string attrNs, XmlValueGetter getter)
+ {
+ }
+
+ private void ValidateEndElementKeyConstraints ()
+ {
+ // Reset Identity constraints.
+ for (int i = 0; i < keyTables.Count; i++) {
+ XsdKeyTable seq = this.keyTables [i] as XsdKeyTable;
+ if (seq.StartDepth == depth) {
+ ValidateEndKeyConstraint (seq);
+ } else {
+ 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 == depth) {
+ if (entry.KeyFound)
+ seq.FinishedEntries.Add (entry);
+ else if (seq.SourceSchemaIdentity is XmlSchemaKey)
+ HandleError ("Key sequence is missing.");
+ seq.Entries.RemoveAt (k);
+ k--;
+ }
+ // Pop validated key depth to find two or more fields.
+ else {
+ for (int j = 0; j < entry.KeyFields.Count; j++) {
+ XsdKeyEntryField kf = entry.KeyFields [j];
+ if (!kf.FieldFound && kf.FieldFoundDepth == depth) {
+ kf.FieldFoundDepth = 0;
+ kf.FieldFoundPath = null;
+ }
+ }
+ }
+ }
+ }
+ }
+ for (int i = 0; i < keyTables.Count; i++) {
+ XsdKeyTable seq = this.keyTables [i] as XsdKeyTable;
+ if (seq.StartDepth == depth) {
+ keyTables.RemoveAt (i);
+ i--;
+ }
+ }
+ }
+
+ private void ValidateEndKeyConstraint (XsdKeyTable seq)
+ {
+ ArrayList errors = new ArrayList ();
+ for (int i = 0; i < seq.Entries.Count; i++) {
+ XsdKeyEntry entry = (XsdKeyEntry) seq.Entries [i];
+ if (entry.KeyFound)
+ continue;
+ if (seq.SourceSchemaIdentity is XmlSchemaKey)
+ errors.Add ("line " + entry.SelectorLineNumber + "position " + entry.SelectorLinePosition);
+ }
+ if (errors.Count > 0)
+ HandleError ("Invalid identity constraints were found. Key was not found. "
+ + String.Join (", ", errors.ToArray (typeof (string)) as string []));
+
+ errors.Clear ();
+ // 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 (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 (errors.Count > 0)
+ HandleError ("Invalid identity constraints were found. Referenced key was not found: "
+ + String.Join (" / ", errors.ToArray (typeof (string)) as string []));
+ }
+ }
+
+ 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, nsResolver);
+ } 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, depth == xsiNilDepth, dt as XsdAnySimpleType, depth, lineInfo))
+ HandleError ("Two or more identical key value was found: '" + value + "' .");
+ this.currentKeyFieldConsumers.RemoveAt (0);
+ }
+ }
+ }
+ #endregion
+
+ #region xsi:type
+ private object GetXsiType (string name)
+ {
+ object xsiType = null;
+ XmlQualifiedName typeQName =
+ XmlQualifiedName.Parse (name, nsResolver);
+ if (typeQName == ComplexType.AnyTypeName)
+ xsiType = ComplexType.AnyType;
+ else if (XmlSchemaUtil.IsBuiltInDatatypeName (typeQName))
+ xsiType = XsDatatype.FromName (typeQName);
+ else
+ xsiType = FindType (typeQName);
+ return xsiType;
+ }
+
+ private void HandleXsiType (string typename)
+ {
+ XsElement element = Context.Element;
+ object xsiType = GetXsiType (typename);
+ if (xsiType == null) {
+ HandleError ("The instance type was not found: " + typename);
+ return;
+ }
+ XmlSchemaType xsiSchemaType = xsiType as XmlSchemaType;
+ if (xsiSchemaType != null && Context.Element != null) {
+ XmlSchemaType elemBaseType = 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 & element.BlockResolved) != 0)
+ HandleError ("The instance type is prohibited by the context element.");
+ }
+ ComplexType xsiComplexType = xsiType as ComplexType;
+ if (xsiComplexType != null && xsiComplexType.IsAbstract)
+ HandleError ("The instance type is abstract: " + typename);
+ else {
+ // If current schema type exists, then this xsi:type must be
+ // valid extension of that type. See 1.2.1.2.4.
+ if (element != null) {
+ AssessLocalTypeDerivationOK (xsiType, element.ElementType, element.BlockResolved);
+ }
+ // See also ValidateEndOfAttributes().
+ Context.XsiType = xsiType;
+ }
}
+ // It is common to ElementLocallyValid::4 and SchemaValidityAssessment::1.2.1.2.4
+ private void AssessLocalTypeDerivationOK (object xsiType, object baseType, XmlSchemaDerivationMethod flag)
+ {
+ XmlSchemaType xsiSchemaType = xsiType as XmlSchemaType;
+ 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)
+ flag |= baseComplexType.BlockResolved;
+ if (flag == XmlSchemaDerivationMethod.All) {
+ HandleError ("Prohibited element type substitution.");
+ return;
+ } else if (xsiSchemaType != null && (flag & xsiSchemaType.DerivedBy) != 0) {
+ HandleError ("Prohibited element type substitution.");
+ return;
+ }
+ }
+
+ if (xsiComplexType != null)
+ try {
+ xsiComplexType.ValidateTypeDerivationOK (baseType, null, null);
+ } catch (ValException ex) {
+ HandleError (ex);
+ }
+ else {
+ SimpleType xsiSimpleType = xsiType as SimpleType;
+ if (xsiSimpleType != null) {
+ try {
+ xsiSimpleType.ValidateTypeDerivationOK (baseType, null, null, true);
+ } catch (ValException ex) {
+ HandleError (ex);
+ }
+ }
+ else if (xsiType is XsDatatype) {
+ // do nothing
+ }
+ else
+ HandleError ("Primitive data type cannot be derived type using xsi:type specification.");
+ }
+ }
#endregion
+
+ private void HandleXsiNil (XmlValueGetter getter, XmlSchemaInfo info)
+ {
+ XsElement element = Context.Element;
+ if (!element.ActualIsNillable) {
+ HandleError (String.Format ("Current element '{0}' is not nillable and thus does not allow occurence of 'nil' attribute.", Context.Element.QualifiedName));
+ return;
+ }
+ string value = getter ().Trim (XmlChar.WhitespaceChars);
+ // 3.2.
+ // Note that 3.2.1 xsi:nil constraints are to be
+ // validated in AssessElementSchemaValidity() and
+ // ValidateCharacters().
+ if (value == "true") {
+ if (element.ValidatedFixedValue != null)
+ HandleError ("Schema instance nil was specified, where the element declaration for " + element.QualifiedName + "has fixed value constraints.");
+ xsiNilDepth = depth;
+ if (info != null)
+ info.IsNil = true;
+ }
+ }
}
}
diff --git a/mcs/class/System.XML/System.Xml.dll.sources b/mcs/class/System.XML/System.Xml.dll.sources
index 5c8fa444f44..bc74d615f51 100755
--- a/mcs/class/System.XML/System.Xml.dll.sources
+++ b/mcs/class/System.XML/System.Xml.dll.sources
@@ -1,5 +1,6 @@
Assembly/AssemblyInfo.cs
Assembly/Locale.cs
+Mono.Xml.Schema/XmlSchemaValidatingReader.cs
Mono.Xml.Schema/XsdIdentityPath.cs
Mono.Xml.Schema/XsdIdentityState.cs
Mono.Xml.Schema/XsdKeyTable.cs
diff --git a/mcs/class/System.XML/System.Xml/ChangeLog b/mcs/class/System.XML/System.Xml/ChangeLog
index e64a82157eb..72ebbc71a36 100644
--- a/mcs/class/System.XML/System.Xml/ChangeLog
+++ b/mcs/class/System.XML/System.Xml/ChangeLog
@@ -1,3 +1,10 @@
+2004-12-14 Atsushi Enomoto <atsushi@ximian.com>
+
+ * XmlReaderSettings.cs : XsdValidate and DtdValidate are now
+ ValidationType.
+ * XmlReader.cs : In Create(), use XmlSchemaValidatingReader for xsd
+ validation.
+
2004-12-12 Zoltan Varga <vargaz@freemail.hu>
* XmlTextReader.cs: Work around a compiler bug in csc 2.0 beta 1.
diff --git a/mcs/class/System.XML/System.Xml/XmlReader.cs b/mcs/class/System.XML/System.Xml/XmlReader.cs
index 981d99514d0..c4aa341c09c 100644
--- a/mcs/class/System.XML/System.Xml/XmlReader.cs
+++ b/mcs/class/System.XML/System.Xml/XmlReader.cs
@@ -281,23 +281,26 @@ namespace System.Xml
private static XmlReader CreateValidatingXmlReader (XmlReader reader, XmlReaderSettings settings)
{
XmlValidatingReader xvr = null;
- if (settings.DtdValidate) {
+ switch (settings.ValidationType) {
+ case ValidationType.DTD:
xvr = new XmlValidatingReader (reader);
- if (!settings.XsdValidate)
- xvr.ValidationType = ValidationType.DTD;
- // otherwise .Auto by default.
- } else if (settings.XsdValidate) {
- xvr = new XmlValidatingReader (reader);
- xvr.ValidationType = ValidationType.Schema;
+ xvr.ValidationType = ValidationType.DTD;
+ break;
+ case ValidationType.Schema:
+// xvr = new XmlValidatingReader (reader);
+// xvr.ValidationType = ValidationType.Schema;
+ return new Mono.Xml.Schema.XmlSchemaValidatingReader (reader, settings);
+ case ValidationType.XDR:
+ throw new NotSupportedException ();
}
if (xvr != null)
xvr.SetSchemas (settings.Schemas);
if ((settings.ValidationFlags & XmlSchemaValidationFlags.IgnoreIdentityConstraints) != 0)
throw new NotImplementedException ();
- if ((settings.ValidationFlags & XmlSchemaValidationFlags.IgnoreInlineSchema) == 0)
+ if ((settings.ValidationFlags & XmlSchemaValidationFlags.IgnoreInlineSchema) != 0)
throw new NotImplementedException ();
- if ((settings.ValidationFlags & XmlSchemaValidationFlags.IgnoreSchemaLocation) == 0)
+ if ((settings.ValidationFlags & XmlSchemaValidationFlags.IgnoreSchemaLocation) != 0)
throw new NotImplementedException ();
if ((settings.ValidationFlags & XmlSchemaValidationFlags.IgnoreValidationWarnings) == 0)
throw new NotImplementedException ();
diff --git a/mcs/class/System.XML/System.Xml/XmlReaderSettings.cs b/mcs/class/System.XML/System.Xml/XmlReaderSettings.cs
index b0f9cde2f66..d477ee3418c 100755
--- a/mcs/class/System.XML/System.Xml/XmlReaderSettings.cs
+++ b/mcs/class/System.XML/System.Xml/XmlReaderSettings.cs
@@ -44,7 +44,6 @@ namespace System.Xml
private bool checkCharacters;
private bool closeInput;
private ConformanceLevel conformance;
- private bool dtdValidate;
private bool ignoreComments;
private bool ignoreProcessingInstructions;
private bool ignoreWhitespace;
@@ -53,8 +52,8 @@ namespace System.Xml
private bool prohibitDtd;
private XmlNameTable nameTable;
private XmlSchemaSet schemas;
- private bool xsdValidate;
private XsValidationFlags validationFlags;
+ private ValidationType validationType;
public XmlReaderSettings ()
{
@@ -66,7 +65,6 @@ namespace System.Xml
checkCharacters = org.checkCharacters;
closeInput = org.closeInput;
conformance = org.conformance;
- dtdValidate = org.dtdValidate;
ignoreComments = org.ignoreComments;
ignoreProcessingInstructions =
org.ignoreProcessingInstructions;
@@ -76,7 +74,7 @@ namespace System.Xml
prohibitDtd = org.prohibitDtd;
schemas = org.schemas;
validationFlags = org.validationFlags;
- xsdValidate = org.xsdValidate;
+ validationType = org.validationType;
nameTable = org.NameTable;
}
@@ -92,7 +90,6 @@ namespace System.Xml
checkCharacters = true;
closeInput = false; // ? not documented
conformance = ConformanceLevel.Document;
- dtdValidate = false;
ignoreComments = false;
ignoreProcessingInstructions = false;
ignoreWhitespace = false;
@@ -104,7 +101,7 @@ namespace System.Xml
XsValidationFlags.IgnoreValidationWarnings
| XsValidationFlags.IgnoreSchemaLocation
| XsValidationFlags.IgnoreInlineSchema;
- xsdValidate = false;
+ validationType = ValidationType.None;
}
public bool CheckCharacters {
@@ -122,11 +119,6 @@ namespace System.Xml
set { conformance = value; }
}
- public bool DtdValidate {
- get { return dtdValidate; }
- set { dtdValidate = value; }
- }
-
public bool IgnoreComments {
get { return ignoreComments; }
set { ignoreComments = value; }
@@ -178,9 +170,9 @@ namespace System.Xml
set { validationFlags = value; }
}
- public bool XsdValidate {
- get { return xsdValidate; }
- set { xsdValidate = value; }
+ public ValidationType ValidationType {
+ get { return validationType; }
+ set { validationType = value; }
}
}
}