diff options
author | Atsushi Eno <atsushieno@gmail.com> | 2004-12-14 15:09:23 +0300 |
---|---|---|
committer | Atsushi Eno <atsushieno@gmail.com> | 2004-12-14 15:09:23 +0300 |
commit | 2ff40096cb78bb837b9d1df6766433ae43b79cdc (patch) | |
tree | 662777b1a8a2a7fdfced98c50d6f4e5e8ffd5c7f /mcs | |
parent | 6e1bb0f3e948e7853bd8af0933d6d6137aaa07c2 (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/ChangeLog | 4 | ||||
-rw-r--r-- | mcs/class/System.XML/Mono.Xml.Schema/ChangeLog | 7 | ||||
-rwxr-xr-x | mcs/class/System.XML/Mono.Xml.Schema/XmlSchemaValidatingReader.cs | 858 | ||||
-rw-r--r-- | mcs/class/System.XML/Mono.Xml.Schema/XsdValidatingReader.cs | 17 | ||||
-rwxr-xr-x | mcs/class/System.XML/System.Xml.Schema/ChangeLog | 4 | ||||
-rwxr-xr-x | mcs/class/System.XML/System.Xml.Schema/XmlSchemaValidator.cs | 1190 | ||||
-rwxr-xr-x | mcs/class/System.XML/System.Xml.dll.sources | 1 | ||||
-rw-r--r-- | mcs/class/System.XML/System.Xml/ChangeLog | 7 | ||||
-rw-r--r-- | mcs/class/System.XML/System.Xml/XmlReader.cs | 21 | ||||
-rwxr-xr-x | mcs/class/System.XML/System.Xml/XmlReaderSettings.cs | 20 |
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; }
}
}
}
|