浏览代码

Added more checking of restriction facets.

2004-01-11  David Sheldon <[email protected]>

  * BuiltInDatatype.cs : Added XsdOrdering enum, and Compare methods
   to the data-types. Changed AllowedFacets to be a bitfield.

  * XmlSchemaFacet.cs : Added Facet enumeration to represent bitfield.

  * XmlSchemaEnumerationFacet.cs,
    XmlSchemaFractionDigitsFacet.cs,
    XmlSchemaLengthFacet.cs,
    XmlSchemaMaxExclusiveFacet.cs,
    XmlSchemaMaxInclusiveFacet.cs,
    XmlSchemaMaxLengthFacet.cs,
    XmlSchemaMinExclusiveFacet.cs,
    XmlSchemaMinInclusiveFacet.cs,
    XmlSchemaMinLengthFacet.cs,
    XmlSchemaNumericFacet.cs,
    XmlSchemaPatternFacet.cs,
    XmlSchemaTotalDigitsFacet.cs,
    XmlSchemaWhiteSpaceFacet.cs : Added ThisFacet Property to return facet type


  * XmlSchemaSimpleTypeRestriction.cs: Inherited facets from base types,
    checked which which were allowed on different types. Validated fixed
    facets, duplicated facets and derivation by restriction. Added checking
    for min/max Inclusive/Exclusive, totalDigits and fractionDigits facets in
    validation.

svn path=/trunk/mcs/; revision=21934
David Sheldon 22 年之前
父节点
当前提交
0ebca37f5d

+ 411 - 116
mcs/class/System.XML/System.Xml.Schema/BuiltInDatatype.cs

@@ -29,6 +29,14 @@ namespace Mono.Xml.Schema
 		Total
 	}
 
+	public enum XsdOrdering 
+	{
+		LessThan = -1,
+		Equal = 0,
+		GreaterThan = 1,
+		Indeterminate = 2
+	}
+	
 	public class XsdAnySimpleType : XmlSchemaDatatype
 	{
 		static XsdAnySimpleType instance;
@@ -81,64 +89,49 @@ namespace Mono.Xml.Schema
 			return this.Normalize (s, XsdWhitespaceFacet.Collapse).Split (whitespaceArray);
 		}
 		
-		internal virtual bool AllowsFacet(XmlSchemaFacet xsf)
-		{
+	
+
 			// Can you even use XsdAnySimpleType in a schema?
 			// -> Yes. See E1-22 of http://www.w3.org/2001/05/xmlschema-errata#Errata1 (somewhat paranoid ;-)
-			return true;
+		
+		internal bool AllowsFacet(XmlSchemaFacet xsf) {
+			return (AllowedFacets & xsf.ThisFacet)!=0;
 		}
 
 
 
-		/* Matches facets allowed on boolean type
-		 */
-		protected static bool BooleanAllowsFacet(XmlSchemaFacet xsf) 
-		{
-			if (xsf is XmlSchemaPatternFacet ||
-					xsf is XmlSchemaWhiteSpaceFacet ) {
-				return true;
+		internal virtual XsdOrdering Compare(object x, object y) {
+			return XsdOrdering.Indeterminate;
 			}
-			return false;
+		
+		// anySimpleType allows any facet
+		internal virtual XmlSchemaFacet.Facet AllowedFacets {
+			get { return XmlSchemaFacet.AllFacets ;}
 		}
 
-		/* Matches facets allowed on decimal type. 
+		/* Matches facets allowed on boolean type
 		 */
+		protected const XmlSchemaFacet.Facet booleanAllowedFacets = 
+					 XmlSchemaFacet.Facet.pattern | XmlSchemaFacet.Facet.whiteSpace;
 
-		protected static bool DecimalAllowsFacet(XmlSchemaFacet xsf) 
-		{
-			if (xsf is XmlSchemaPatternFacet ||
-					xsf is XmlSchemaEnumerationFacet ||
-					xsf is XmlSchemaWhiteSpaceFacet ||
-					xsf is XmlSchemaMaxInclusiveFacet ||
-					xsf is XmlSchemaMaxExclusiveFacet ||
-					xsf is XmlSchemaMinInclusiveFacet ||
-					xsf is XmlSchemaMinExclusiveFacet || 
-					xsf is XmlSchemaFractionDigitsFacet || 
-					xsf is XmlSchemaTotalDigitsFacet) {
-				return true;
-			}
-			return false;
-		}
-
+		/* Matches facets allowed on decimal type. 
+		 */
+		protected const XmlSchemaFacet.Facet decimalAllowedFacets = 
+							XmlSchemaFacet.Facet.pattern | XmlSchemaFacet.Facet.enumeration | 
+							XmlSchemaFacet.Facet.whiteSpace | XmlSchemaFacet.Facet.maxInclusive | 
+							XmlSchemaFacet.Facet.minInclusive | XmlSchemaFacet.Facet.maxExclusive | 
+							XmlSchemaFacet.Facet.minExclusive | XmlSchemaFacet.Facet.fractionDigits | 
+							XmlSchemaFacet.Facet.totalDigits ;
 
 		/* Matches facets allowed on float, double, duration, dateTime, time, date,
 		 * gYearMonth, gYear, gMonthDay, gMonth, and gDay types
 		 */
 
-		protected static bool DurationAllowsFacet(XmlSchemaFacet xsf) 
-		{
-			if (xsf is XmlSchemaPatternFacet ||
-					xsf is XmlSchemaEnumerationFacet ||
-					xsf is XmlSchemaWhiteSpaceFacet ||
-					xsf is XmlSchemaMaxInclusiveFacet ||
-					xsf is XmlSchemaMaxExclusiveFacet ||
-					xsf is XmlSchemaMinInclusiveFacet ||
-					xsf is XmlSchemaMinExclusiveFacet ) {
-				return true;
-			}
-			return false;
-		}
-
+		protected const XmlSchemaFacet.Facet durationAllowedFacets = 
+							XmlSchemaFacet.Facet.pattern | XmlSchemaFacet.Facet.enumeration | 
+							XmlSchemaFacet.Facet.whiteSpace | XmlSchemaFacet.Facet.maxInclusive |
+							XmlSchemaFacet.Facet.minInclusive | XmlSchemaFacet.Facet.maxExclusive |
+							XmlSchemaFacet.Facet.minExclusive ;
 
 		/* Matches facet allowed on string, hexBinary, base64Binary,
 		 * anyURI, QName and NOTATION types 
@@ -146,18 +139,10 @@ namespace Mono.Xml.Schema
 		 * Also used on list types
 		 */
 
-		protected static bool StringAllowsFacet(XmlSchemaFacet xsf) 
-		{
-			if (xsf is XmlSchemaLengthFacet ||
-					xsf is XmlSchemaMinLengthFacet || 
-					xsf is XmlSchemaMaxLengthFacet ||
-					xsf is XmlSchemaPatternFacet ||
-					xsf is XmlSchemaEnumerationFacet ||
-					xsf is XmlSchemaWhiteSpaceFacet) {
-				return true;
-			}
-			return false;
-		}
+		protected const XmlSchemaFacet.Facet stringAllowedFacets = 
+						 XmlSchemaFacet.Facet.length | XmlSchemaFacet.Facet.minLength |
+						 XmlSchemaFacet.Facet.maxLength | XmlSchemaFacet.Facet.pattern | 
+						 XmlSchemaFacet.Facet.enumeration | XmlSchemaFacet.Facet.whiteSpace; 
 	}
 
 	// xs:string
@@ -167,6 +152,10 @@ namespace Mono.Xml.Schema
 		{
 		}
 
+		internal override XmlSchemaFacet.Facet AllowedFacets {
+			get { return stringAllowedFacets; } 
+		}
+
 		public override XmlTokenizedType TokenizedType {
 			get { return XmlTokenizedType.CDATA; }
 		}
@@ -200,10 +189,6 @@ namespace Mono.Xml.Schema
 		public string Pattern;
 		public ICollection Enumeration;
 		*/
-		internal override bool AllowsFacet(XmlSchemaFacet xsf) 
-		{
-			return StringAllowsFacet(xsf);
-		}
 	
 	}
 
@@ -420,7 +405,6 @@ namespace Mono.Xml.Schema
 	public class XsdEntity : XsdName
 	{
 		internal XsdEntity ()
-
 		{
 		}
 
@@ -464,6 +448,10 @@ namespace Mono.Xml.Schema
 		{
 		}
 
+		internal override XmlSchemaFacet.Facet AllowedFacets {
+			get { return stringAllowedFacets; } 
+		}
+
 		public override XmlTokenizedType TokenizedType {
 			get { return XmlTokenizedType.NOTATION; }
 		}
@@ -503,10 +491,6 @@ namespace Mono.Xml.Schema
 		public ICollection Enumeration;
 
 
-		internal override bool AllowsFacet(XmlSchemaFacet xsf) 
-		{
-			return StringAllowsFacet(xsf);
-		}
 
 
 	}
@@ -519,6 +503,10 @@ namespace Mono.Xml.Schema
 			this.WhitespaceValue = XsdWhitespaceFacet.Collapse;
 		}
 
+		internal override XmlSchemaFacet.Facet AllowedFacets {
+			get { return decimalAllowedFacets; } 
+		}
+
 		public override XmlTokenizedType TokenizedType {
 			get { return XmlTokenizedType.None; }
 		}
@@ -533,6 +521,23 @@ namespace Mono.Xml.Schema
 			return XmlConvert.ToDecimal (this.Normalize (s));
 		}
 
+	 
+		internal override XsdOrdering Compare(object x, object y) {
+			if ((x is Decimal) && (y is Decimal)) {
+				int ret = Decimal.Compare((Decimal)x, (Decimal)y);
+				if (ret < 0) { 
+					return XsdOrdering.LessThan;
+				}
+				else if (ret > 0) {
+					return XsdOrdering.GreaterThan;
+				}
+				else {
+					return XsdOrdering.Equal;
+				}
+			}
+			return XsdOrdering.Indeterminate;
+		}
+		
 		// Fundamental Facets
 		public override bool Bounded {
 			get { return false; }
@@ -558,10 +563,6 @@ namespace Mono.Xml.Schema
 		public ICollection Enumeration;
 		
 		
-		internal override bool AllowsFacet(XmlSchemaFacet xsf) 
-		{
-			return DecimalAllowsFacet(xsf);
-		}
 		
 		
 	}
@@ -586,6 +587,9 @@ namespace Mono.Xml.Schema
 				throw new FormatException ("Integer contains point number.");
 			return d;
 		}
+	 
+		
+	
 	}
 
 	// xs:Long
@@ -600,6 +604,21 @@ namespace Mono.Xml.Schema
 		{
 			return XmlConvert.ToInt64 (Normalize (s));
 		}
+		
+		internal override XsdOrdering Compare(object x, object y) {
+			if ((x is long) && (y is long)) {
+				if ((long)x==(long)y) {
+					return XsdOrdering.Equal;
+				}
+				else if ((long)x<(long)y) {
+					return XsdOrdering.LessThan;
+				}
+				else {
+					return XsdOrdering.GreaterThan;
+				}
+			}
+			return XsdOrdering.Indeterminate;
+		}
 	}
 
 	// xs:Int
@@ -614,6 +633,20 @@ namespace Mono.Xml.Schema
 		{
 			return XmlConvert.ToInt32 (Normalize (s));
 		}
+		internal override XsdOrdering Compare(object x, object y) {
+			if ((x is int) && (y is int)) {
+				if ((int)x==(int)y) {
+					return XsdOrdering.Equal;
+				}
+				else if ((int)x<(int)y) {
+					return XsdOrdering.LessThan;
+				}
+				else {
+					return XsdOrdering.GreaterThan;
+				}
+			}
+			return XsdOrdering.Indeterminate;
+		}
 	}
 
 
@@ -629,6 +662,20 @@ namespace Mono.Xml.Schema
 		{
 			return XmlConvert.ToInt16 (Normalize (s));
 		}
+		internal override XsdOrdering Compare(object x, object y) {
+			if ((x is short) && (y is short)) {
+				if ((short)x==(short)y) {
+					return XsdOrdering.Equal;
+				}
+				else if ((short)x<(short)y) {
+					return XsdOrdering.LessThan;
+				}
+				else {
+					return XsdOrdering.GreaterThan;
+				}
+			}
+			return XsdOrdering.Indeterminate;
+		}
 	}
 
 	// xs:Byte
@@ -643,6 +690,20 @@ namespace Mono.Xml.Schema
 		{
 			return XmlConvert.ToSByte (Normalize (s));
 		}
+		internal override XsdOrdering Compare(object x, object y) {
+			if ((x is sbyte) && (y is sbyte)) {
+				if ((sbyte)x==(sbyte)y) {
+					return XsdOrdering.Equal;
+				}
+				else if ((sbyte)x<(sbyte)y) {
+					return XsdOrdering.LessThan;
+				}
+				else {
+					return XsdOrdering.GreaterThan;
+				}
+			}
+			return XsdOrdering.Indeterminate;
+		}
 	}
 
 	// xs:nonNegativeInteger
@@ -674,6 +735,20 @@ namespace Mono.Xml.Schema
 		{
 			return XmlConvert.ToUInt64 (Normalize (s));
 		}
+		internal override XsdOrdering Compare(object x, object y) {
+			if ((x is ulong) && (y is ulong)) {
+				if ((ulong)x==(ulong)y) {
+					return XsdOrdering.Equal;
+				}
+				else if ((ulong)x<(ulong)y) {
+					return XsdOrdering.LessThan;
+				}
+				else {
+					return XsdOrdering.GreaterThan;
+				}
+			}
+			return XsdOrdering.Indeterminate;
+		}
 	}
 
 	// xs:unsignedInt
@@ -689,6 +764,20 @@ namespace Mono.Xml.Schema
 		{
 			return XmlConvert.ToUInt32 (Normalize (s));
 		}
+		internal override XsdOrdering Compare(object x, object y) {
+			if ((x is uint) && (y is uint)) {
+				if ((uint)x==(uint)y) {
+					return XsdOrdering.Equal;
+				}
+				else if ((uint)x<(uint)y) {
+					return XsdOrdering.LessThan;
+				}
+				else {
+					return XsdOrdering.GreaterThan;
+				}
+			}
+			return XsdOrdering.Indeterminate;
+		}
 	}
 
 
@@ -705,6 +794,20 @@ namespace Mono.Xml.Schema
 		{
 			return XmlConvert.ToUInt16 (Normalize (s));
 		}
+		internal override XsdOrdering Compare(object x, object y) {
+			if ((x is ushort) && (y is ushort)) {
+				if ((ushort)x==(ushort)y) {
+					return XsdOrdering.Equal;
+				}
+				else if ((ushort)x<(ushort)y) {
+					return XsdOrdering.LessThan;
+				}
+				else {
+					return XsdOrdering.GreaterThan;
+				}
+			}
+			return XsdOrdering.Indeterminate;
+		}
 	}
 
 	// xs:unsignedByte
@@ -720,6 +823,20 @@ namespace Mono.Xml.Schema
 		{
 			return XmlConvert.ToByte(Normalize (s));
 		}
+		internal override XsdOrdering Compare(object x, object y) {
+			if ((x is byte) && (y is byte)) {
+				if ((byte)x==(byte)y) {
+					return XsdOrdering.Equal;
+				}
+				else if ((byte)x<(byte)y) {
+					return XsdOrdering.LessThan;
+				}
+				else {
+					return XsdOrdering.GreaterThan;
+				}
+			}
+			return XsdOrdering.Indeterminate;
+		}
 	}
 
 
@@ -777,6 +894,10 @@ namespace Mono.Xml.Schema
 			this.WhitespaceValue = XsdWhitespaceFacet.Collapse;
 		}
     
+		internal override XmlSchemaFacet.Facet AllowedFacets {
+			get { return durationAllowedFacets; } 
+		}
+		
 		// Fundamental Facets
 		public override bool Bounded {
 			get { return true; }
@@ -800,11 +921,21 @@ namespace Mono.Xml.Schema
 		{
 			return XmlConvert.ToSingle (Normalize (s));
 		}
-		
-		internal override bool AllowsFacet(XmlSchemaFacet xsf) 
-		{
-			return DurationAllowsFacet(xsf);
+		internal override XsdOrdering Compare(object x, object y) {
+			if ((x is float) && (y is float)) {
+				if ((float)x==(float)y) {
+					return XsdOrdering.Equal;
+				}
+				else if ((float)x<(float)y) {
+					return XsdOrdering.LessThan;
+				}
+				else {
+					return XsdOrdering.GreaterThan;
+				}
 		}
+			return XsdOrdering.Indeterminate;
+		}
+		
 	}
 
 	// xs:double
@@ -815,6 +946,10 @@ namespace Mono.Xml.Schema
 			this.WhitespaceValue = XsdWhitespaceFacet.Collapse;
 		}
     
+		internal override XmlSchemaFacet.Facet AllowedFacets {
+			get { return durationAllowedFacets; } 
+		}
+		
 		// Fundamental Facets
 		public override bool Bounded {
 			get { return true; }
@@ -838,11 +973,21 @@ namespace Mono.Xml.Schema
 		{
 			return XmlConvert.ToDouble (Normalize (s));
 		}
-		
-		internal override bool AllowsFacet(XmlSchemaFacet xsf) 
-		{
-			return DurationAllowsFacet(xsf);
+		internal override XsdOrdering Compare(object x, object y) {
+			if ((x is double) && (y is double)) {
+				if ((double)x==(double)y) {
+					return XsdOrdering.Equal;
+				}
+				else if ((double)x<(double)y) {
+					return XsdOrdering.LessThan;
+		}
+				else {
+					return XsdOrdering.GreaterThan;
+				}
+			}
+			return XsdOrdering.Indeterminate;
 		}
+		
 	}
 
 	// xs:base64Binary
@@ -871,6 +1016,10 @@ namespace Mono.Xml.Schema
       this.WhitespaceValue = XsdWhitespaceFacet.Collapse;
 		}
 
+		internal override XmlSchemaFacet.Facet AllowedFacets {
+			get { return stringAllowedFacets; } 
+		}
+
 		public override XmlTokenizedType TokenizedType {
 			get { return XmlTokenizedType.None; }
 		}
@@ -885,10 +1034,6 @@ namespace Mono.Xml.Schema
 			return XmlConvert.FromBinHexString (Normalize (s));
 		}
 		
-		internal override bool AllowsFacet(XmlSchemaFacet xsf) 
-		{
-			return StringAllowsFacet(xsf);
-		}
 
 		// Fundamental Facets ... no need to override
 	}
@@ -935,6 +1080,10 @@ namespace Mono.Xml.Schema
       this.WhitespaceValue = XsdWhitespaceFacet.Collapse;
 		}
 
+		internal override XmlSchemaFacet.Facet AllowedFacets {
+			get { return booleanAllowedFacets; } 
+		}
+
 		public override XmlTokenizedType TokenizedType {
 			get { return XmlTokenizedType.CDATA; }
 		}
@@ -964,10 +1113,6 @@ namespace Mono.Xml.Schema
 		}
 		
 		
-		internal override bool AllowsFacet(XmlSchemaFacet xsf) 
-		{
-			return BooleanAllowsFacet(xsf);
-		}
 	}
 
 	// xs:anyURI
@@ -997,6 +1142,10 @@ namespace Mono.Xml.Schema
       this.WhitespaceValue = XsdWhitespaceFacet.Collapse;
 		}
 
+		internal override XmlSchemaFacet.Facet AllowedFacets {
+			get { return durationAllowedFacets; } 
+		}
+
 		public override XmlTokenizedType TokenizedType {
 			get { return XmlTokenizedType.CDATA; }
 		}
@@ -1011,6 +1160,29 @@ namespace Mono.Xml.Schema
 			return XmlConvert.ToTimeSpan (Normalize (s));
 		}
 
+		internal override XsdOrdering Compare(object x, object y) {
+			/* FIXME: This is really simple so far 
+			 *
+			 * In fact in order to do this correctly in XmlSchema, we cannot use TimeSpan as the base type
+			 * Though it turns out that MS .NET is a little broken in this regard too. Not doing comparisons 
+			 * correctly.
+			 */
+			if ((x is TimeSpan) && (y is TimeSpan)) {
+				int ret = TimeSpan.Compare((TimeSpan)x, (TimeSpan)y);
+				if (ret < 0) { 
+					return XsdOrdering.LessThan;
+				}
+				else if (ret > 0) {
+					return XsdOrdering.GreaterThan;
+				}
+				else {
+					return XsdOrdering.Equal;
+				}
+			}
+			return XsdOrdering.Indeterminate;
+		}
+
+		
 		// Fundamental Facets
 		public override bool Bounded {
 			get { return false; }
@@ -1023,14 +1195,8 @@ namespace Mono.Xml.Schema
 		}
 		public override XsdOrderedFacet Ordered {
 			get { return XsdOrderedFacet.Partial; }
-		}
 	 
-		internal override bool AllowsFacet(XmlSchemaFacet xsf) 
-		{
-			return DurationAllowsFacet(xsf);
 		}
-
-		
 	}
 
 	// xs:dateTime
@@ -1041,6 +1207,10 @@ namespace Mono.Xml.Schema
 			this.WhitespaceValue = XsdWhitespaceFacet.Collapse;
 		}
 
+		internal override XmlSchemaFacet.Facet AllowedFacets {
+			get { return durationAllowedFacets; } 
+		}
+
 		public override XmlTokenizedType TokenizedType {
 			get { return XmlTokenizedType.CDATA; }
 		}
@@ -1055,6 +1225,23 @@ namespace Mono.Xml.Schema
 			return XmlConvert.ToDateTime (Normalize (s));
 		}
 
+		internal override XsdOrdering Compare(object x, object y) {
+			/* Really simple so far */
+			if ((x is DateTime) && (y is DateTime)) {
+				int ret = DateTime.Compare((DateTime)x, (DateTime)y);
+				if (ret < 0) { 
+					return XsdOrdering.LessThan;
+				}
+				else if (ret > 0) {
+					return XsdOrdering.GreaterThan;
+				}
+				else {
+					return XsdOrdering.Equal;
+				}
+			}
+			return XsdOrdering.Indeterminate;
+		}
+
 		// Fundamental Facets
 		public override bool Bounded {
 			get { return false; }
@@ -1069,10 +1256,6 @@ namespace Mono.Xml.Schema
 			get { return XsdOrderedFacet.Partial; }
 		}
 		
-		internal override bool AllowsFacet(XmlSchemaFacet xsf) 
-		{
-			return DurationAllowsFacet(xsf);
-		}
 	}
 
 	// xs:date
@@ -1083,6 +1266,10 @@ namespace Mono.Xml.Schema
 			this.WhitespaceValue = XsdWhitespaceFacet.Collapse;
 		}
     
+		internal override XmlSchemaFacet.Facet AllowedFacets {
+			get { return durationAllowedFacets; } 
+		}
+		
 		public override XmlTokenizedType TokenizedType {
 			get { return XmlTokenizedType.CDATA; }
 		}
@@ -1097,15 +1284,27 @@ namespace Mono.Xml.Schema
 			return DateTime.ParseExact (Normalize (s), "yyyy-MM-dd", null);
 		}
 
+		internal override XsdOrdering Compare(object x, object y) {
+			/* Really simple so far */
+			if ((x is DateTime) && (y is DateTime)) {
+				int ret = DateTime.Compare((DateTime)x, (DateTime)y);
+				if (ret < 0) { 
+					return XsdOrdering.LessThan;
+				}
+				else if (ret > 0) {
+					return XsdOrdering.GreaterThan;
+				}
+				else {
+					return XsdOrdering.Equal;
+				}
+			}
+			return XsdOrdering.Indeterminate;
+		}
 		// Fundamental Facets ... no need to override except for Ordered.
 		public override XsdOrderedFacet Ordered {
 			get { return XsdOrderedFacet.Partial; }
 		}
 		
-		internal override bool AllowsFacet(XmlSchemaFacet xsf) 
-		{
-			return DurationAllowsFacet(xsf);
-		}
 	}
 
 	// xs:time
@@ -1143,6 +1342,10 @@ namespace Mono.Xml.Schema
 			this.WhitespaceValue = XsdWhitespaceFacet.Collapse;
 		}
 
+		internal override XmlSchemaFacet.Facet AllowedFacets {
+			get { return durationAllowedFacets; } 
+		}
+
 		public override XmlTokenizedType TokenizedType {
 			get { return XmlTokenizedType.CDATA; }
 		}
@@ -1157,15 +1360,27 @@ namespace Mono.Xml.Schema
 			return DateTime.ParseExact (Normalize (s), timeFormats, null, DateTimeStyles.None);
 		}
 
+		internal override XsdOrdering Compare(object x, object y) {
+			/* Really simple so far */
+			if ((x is DateTime) && (y is DateTime)) {
+				int ret = DateTime.Compare((DateTime)x, (DateTime)y);
+				if (ret < 0) { 
+					return XsdOrdering.LessThan;
+				}
+				else if (ret > 0) {
+					return XsdOrdering.GreaterThan;
+				}
+				else {
+					return XsdOrdering.Equal;
+				}
+			}
+			return XsdOrdering.Indeterminate;
+		}
 		// Fundamental Facets ... no need to override except for Ordered.
 		public override XsdOrderedFacet Ordered {
 			get { return XsdOrderedFacet.Partial; }
 		}
 		
-		internal override bool AllowsFacet(XmlSchemaFacet xsf) 
-		{
-			return DurationAllowsFacet(xsf);
-		}
 	}
 
 	// xs:gYearMonth
@@ -1176,6 +1391,10 @@ namespace Mono.Xml.Schema
 			this.WhitespaceValue = XsdWhitespaceFacet.Collapse;
 		}
     
+		internal override XmlSchemaFacet.Facet AllowedFacets {
+			get { return durationAllowedFacets; } 
+		}
+		
 		public override Type ValueType {
 			get { return typeof (DateTime); }
 		}
@@ -1186,9 +1405,21 @@ namespace Mono.Xml.Schema
 			return DateTime.ParseExact (Normalize (s), "yyyy-MM", null);
 		}
 		
-		internal override bool AllowsFacet(XmlSchemaFacet xsf) 
-		{
-			return DurationAllowsFacet(xsf);
+		internal override XsdOrdering Compare(object x, object y) {
+			/* Really simple so far */
+			if ((x is DateTime) && (y is DateTime)) {
+				int ret = DateTime.Compare((DateTime)x, (DateTime)y);
+				if (ret < 0) { 
+					return XsdOrdering.LessThan;
+				}
+				else if (ret > 0) {
+					return XsdOrdering.GreaterThan;
+				}
+				else {
+					return XsdOrdering.Equal;
+				}
+			}
+			return XsdOrdering.Indeterminate;
 		}
 	}
 
@@ -1200,6 +1431,10 @@ namespace Mono.Xml.Schema
 			this.WhitespaceValue = XsdWhitespaceFacet.Collapse;
 		}
     
+		internal override XmlSchemaFacet.Facet AllowedFacets {
+			get { return durationAllowedFacets; } 
+		}
+		
 		public override Type ValueType {
 			get { return typeof (DateTime); }
 		}
@@ -1210,9 +1445,21 @@ namespace Mono.Xml.Schema
 			return DateTime.ParseExact (Normalize (s), "--MM-dd", null);
 		}
 		
-		internal override bool AllowsFacet(XmlSchemaFacet xsf) 
-		{
-			return DurationAllowsFacet(xsf);
+		internal override XsdOrdering Compare(object x, object y) {
+			/* Really simple so far */
+			if ((x is DateTime) && (y is DateTime)) {
+				int ret = DateTime.Compare((DateTime)x, (DateTime)y);
+				if (ret < 0) { 
+					return XsdOrdering.LessThan;
+				}
+				else if (ret > 0) {
+					return XsdOrdering.GreaterThan;
+				}
+				else {
+					return XsdOrdering.Equal;
+				}
+			}
+			return XsdOrdering.Indeterminate;
 		}
 	}
 
@@ -1224,6 +1471,10 @@ namespace Mono.Xml.Schema
 			this.WhitespaceValue = XsdWhitespaceFacet.Collapse;
 		}
 		
+		internal override XmlSchemaFacet.Facet AllowedFacets {
+			get { return durationAllowedFacets; } 
+		}
+		
     public override Type ValueType {
 			get { return typeof (DateTime); }
 		}
@@ -1236,9 +1487,21 @@ namespace Mono.Xml.Schema
 			return DateTime.ParseExact (Normalize(s), "yyyy", null);
 		}
 		
-		internal override bool AllowsFacet(XmlSchemaFacet xsf) 
-		{
-			return DurationAllowsFacet(xsf);
+		internal override XsdOrdering Compare(object x, object y) {
+			/* Really simple so far */
+			if ((x is DateTime) && (y is DateTime)) {
+				int ret = DateTime.Compare((DateTime)x, (DateTime)y);
+				if (ret < 0) { 
+					return XsdOrdering.LessThan;
+				}
+				else if (ret > 0) {
+					return XsdOrdering.GreaterThan;
+				}
+				else {
+					return XsdOrdering.Equal;
+				}
+			}
+			return XsdOrdering.Indeterminate;
 		}
 	}
 
@@ -1250,6 +1513,10 @@ namespace Mono.Xml.Schema
 			this.WhitespaceValue = XsdWhitespaceFacet.Collapse;
 		}
 		
+		internal override XmlSchemaFacet.Facet AllowedFacets {
+			get { return durationAllowedFacets; } 
+		}
+		
 		public override Type ValueType {
 			get { return typeof (DateTime); }
 		}
@@ -1260,9 +1527,21 @@ namespace Mono.Xml.Schema
 			return DateTime.ParseExact (Normalize(s), "--MM--", null);
 		}
 		
-		internal override bool AllowsFacet(XmlSchemaFacet xsf) 
-		{
-			return DurationAllowsFacet(xsf);
+		internal override XsdOrdering Compare(object x, object y) {
+			/* Really simple so far */
+			if ((x is DateTime) && (y is DateTime)) {
+				int ret = DateTime.Compare((DateTime)x, (DateTime)y);
+				if (ret < 0) { 
+					return XsdOrdering.LessThan;
+				}
+				else if (ret > 0) {
+					return XsdOrdering.GreaterThan;
+				}
+				else {
+					return XsdOrdering.Equal;
+				}
+			}
+			return XsdOrdering.Indeterminate;
 		}
 	}
 
@@ -1274,6 +1553,10 @@ namespace Mono.Xml.Schema
 			this.WhitespaceValue = XsdWhitespaceFacet.Collapse;
 		}
 		
+		internal override XmlSchemaFacet.Facet AllowedFacets {
+			get { return durationAllowedFacets; } 
+		}
+		
 		public override Type ValueType {
 			get { return typeof (DateTime); }
 		}
@@ -1284,9 +1567,21 @@ namespace Mono.Xml.Schema
 			return DateTime.ParseExact (Normalize(s), "---dd", null);
 		}
 		
-		internal override bool AllowsFacet(XmlSchemaFacet xsf) 
-		{
-			return DurationAllowsFacet(xsf);
+		internal override XsdOrdering Compare(object x, object y) {
+			/* Really simple so far */
+			if ((x is DateTime) && (y is DateTime)) {
+				int ret = DateTime.Compare((DateTime)x, (DateTime)y);
+				if (ret < 0) { 
+					return XsdOrdering.LessThan;
+				}
+				else if (ret > 0) {
+					return XsdOrdering.GreaterThan;
+				}
+				else {
+					return XsdOrdering.Equal;
+				}
+			}
+			return XsdOrdering.Indeterminate;
 		}
 	}
 

+ 28 - 0
mcs/class/System.XML/System.Xml.Schema/ChangeLog

@@ -1,3 +1,31 @@
+2004-01-11  David Sheldon <[email protected]>
+
+  * BuiltInDatatype.cs : Added XsdOrdering enum, and Compare methods
+   to the data-types. Changed AllowedFacets to be a bitfield.
+  
+  * XmlSchemaFacet.cs : Added Facet enumeration to represent bitfield.
+
+  * XmlSchemaEnumerationFacet.cs,
+    XmlSchemaFractionDigitsFacet.cs,
+    XmlSchemaLengthFacet.cs,
+    XmlSchemaMaxExclusiveFacet.cs,
+    XmlSchemaMaxInclusiveFacet.cs,
+    XmlSchemaMaxLengthFacet.cs,
+    XmlSchemaMinExclusiveFacet.cs,
+    XmlSchemaMinInclusiveFacet.cs,
+    XmlSchemaMinLengthFacet.cs,
+    XmlSchemaNumericFacet.cs,
+    XmlSchemaPatternFacet.cs,
+    XmlSchemaTotalDigitsFacet.cs,
+    XmlSchemaWhiteSpaceFacet.cs : Added ThisFacet Property to return facet type
+
+
+  * XmlSchemaSimpleTypeRestriction.cs: Inherited facets from base types,
+    checked which which were allowed on different types. Validated fixed
+    facets, duplicated facets and derivation by restriction. Added checking 
+    for min/max Inclusive/Exclusive, totalDigits and fractionDigits facets in 
+    validation.
+
 2004-01-08  Atsushi Enomoto  <[email protected]>
 
 	* BUGS-MS.txt : added list derivation and facet case.

+ 5 - 0
mcs/class/System.XML/System.Xml.Schema/XmlSchemaEnumerationFacet.cs

@@ -15,6 +15,11 @@ namespace System.Xml.Schema
 		{
 		}
 
+		internal override Facet ThisFacet { 
+			get { return Facet.enumeration;}
+		}
+	
+
 		//<enumeration
 		//  id = ID
 		//  value = anySimpleType

+ 27 - 0
mcs/class/System.XML/System.Xml.Schema/XmlSchemaFacet.cs

@@ -7,11 +7,38 @@ using System.ComponentModel;
 
 namespace System.Xml.Schema
 {
+			
 	/// <summary>
 	/// Summary description for XmlSchemaFacet.
 	/// </summary>
 	public abstract class XmlSchemaFacet : XmlSchemaAnnotated
 	{
+		[Flags]
+		internal protected enum Facet {
+			None = 0,
+			length = 1 ,
+			minLength = 2,
+			maxLength = 4,
+			pattern = 8,
+			enumeration = 16,
+			whiteSpace = 32,
+			maxInclusive = 64,
+			maxExclusive = 128,
+			minExclusive = 256,
+			minInclusive = 512, 
+			totalDigits = 1024,
+			fractionDigits = 2048
+		};
+ 
+		internal protected const Facet AllFacets = 
+		                        Facet.length | Facet.minLength |  Facet.maxLength |
+					Facet.minExclusive | Facet.maxExclusive |
+					Facet.minInclusive | Facet.maxInclusive |
+					Facet.pattern | Facet.enumeration | Facet.whiteSpace |
+					Facet.totalDigits | Facet.fractionDigits;
+		
+		internal abstract Facet ThisFacet { get ; }
+		
 		private bool isFixed;
 		private string val;
 

+ 4 - 0
mcs/class/System.XML/System.Xml.Schema/XmlSchemaFractionDigitsFacet.cs

@@ -16,6 +16,10 @@ namespace System.Xml.Schema
 		{
 		}
 
+		internal override Facet ThisFacet { 
+			get { return Facet.fractionDigits;}
+		}
+
 		//<fractionDigits
 		//  fixed = boolean : false
 		//  id = ID

+ 4 - 0
mcs/class/System.XML/System.Xml.Schema/XmlSchemaLengthFacet.cs

@@ -16,6 +16,10 @@ namespace System.Xml.Schema
 		{
 		}
 
+		internal override Facet ThisFacet {
+			get { return Facet.length ; }
+		}
+		
 		//<length
 		//	fixed = boolean : false
 		//	id = ID

+ 4 - 0
mcs/class/System.XML/System.Xml.Schema/XmlSchemaMaxExclusiveFacet.cs

@@ -16,6 +16,10 @@ namespace System.Xml.Schema
 		{
 		}
 
+		internal override Facet ThisFacet { 
+			get { return Facet.maxExclusive;}
+		}
+
 		//<maxExclusive
 		//  fixed = boolean : false
 		//  id = ID

+ 4 - 0
mcs/class/System.XML/System.Xml.Schema/XmlSchemaMaxInclusiveFacet.cs

@@ -16,6 +16,10 @@ namespace System.Xml.Schema
 		{
 		}
 
+		internal override Facet ThisFacet {
+			get { return Facet.maxInclusive;}
+		}
+
 		//<maxInclusive
 		//  fixed = boolean : false
 		//  id = ID

+ 5 - 0
mcs/class/System.XML/System.Xml.Schema/XmlSchemaMaxLengthFacet.cs

@@ -16,6 +16,11 @@ namespace System.Xml.Schema
 		{
 		}
 
+		internal override Facet ThisFacet { 
+			get { return Facet.maxLength;}
+		}
+	
+
 		//<maxLength
 		//  fixed = boolean : false
 		//  id = ID

+ 4 - 0
mcs/class/System.XML/System.Xml.Schema/XmlSchemaMinExclusiveFacet.cs

@@ -16,6 +16,10 @@ namespace System.Xml.Schema
 		{
 		}
 
+		internal override Facet ThisFacet {
+			get { return Facet.minExclusive; }
+		}
+
 		//<minExclusive
 		//  fixed = boolean : false
 		//  id = ID

+ 5 - 0
mcs/class/System.XML/System.Xml.Schema/XmlSchemaMinInclusiveFacet.cs

@@ -15,6 +15,11 @@ namespace System.Xml.Schema
 		public XmlSchemaMinInclusiveFacet()
 		{
 		}
+			
+		internal override Facet ThisFacet {
+			get { return Facet.minInclusive ;}
+		}
+
 		//<minInclusive
 		//  fixed = boolean : false
 		//  id = ID

+ 5 - 0
mcs/class/System.XML/System.Xml.Schema/XmlSchemaMinLengthFacet.cs

@@ -16,6 +16,11 @@ namespace System.Xml.Schema
 		{
 		}
 
+		internal override Facet ThisFacet {
+			get { return Facet.minLength;}
+		}
+		
+		
 		//<minLength
 		//  fixed = boolean : false
 		//  id = ID

+ 5 - 0
mcs/class/System.XML/System.Xml.Schema/XmlSchemaPatternFacet.cs

@@ -15,6 +15,11 @@ namespace System.Xml.Schema
 		public XmlSchemaPatternFacet()
 		{
 		}
+			
+		internal override Facet ThisFacet { 
+			get { return Facet.pattern;}
+		}
+	
 		//<pattern
 		//  id = ID
 		//  value = anySimpleType

+ 359 - 42
mcs/class/System.XML/System.Xml.Schema/XmlSchemaSimpleTypeRestriction.cs

@@ -27,6 +27,14 @@ namespace System.Xml.Schema
 		private decimal minLengthFacet;
 		private decimal fractionDigitsFacet;
 		private decimal totalDigitsFacet;
+		private object maxInclusiveFacet ;
+		private object maxExclusiveFacet ;
+		private object minInclusiveFacet ;
+		private object minExclusiveFacet ;
+		private XmlSchemaFacet.Facet fixedFacets = XmlSchemaFacet.Facet.None; 
+		
+		
+		private static NumberStyles lengthStyle = NumberStyles.Integer;
 
 		public XmlSchemaSimpleTypeRestriction()
 		{
@@ -99,6 +107,13 @@ namespace System.Xml.Schema
 		/** Checks if this facet is valid on this restriction. Does not check that it has
 			* not been fixed in the baseType. That is done elsewhere.
 			*/
+		
+		private const XmlSchemaFacet.Facet listFacets =
+						 XmlSchemaFacet.Facet.length | XmlSchemaFacet.Facet.minLength |
+						 XmlSchemaFacet.Facet.maxLength | XmlSchemaFacet.Facet.pattern | 
+						 XmlSchemaFacet.Facet.enumeration | XmlSchemaFacet.Facet.whiteSpace; 
+ 
+		
 		private bool IsAllowedFacet(XmlSchemaFacet xsf) {
 		/* Must be called after this.ValidateActualType, as it uses actualBaseSchemaType */
 
@@ -116,12 +131,7 @@ namespace System.Xml.Schema
 				 }
 				 XmlSchemaSimpleTypeList stl = st as XmlSchemaSimpleTypeList;
 				 if (stl != null) {
-					 return (xsf is XmlSchemaLengthFacet || 
-									 xsf is XmlSchemaMaxLengthFacet ||
-									 xsf is XmlSchemaMinLengthFacet ||
-									 xsf is XmlSchemaPatternFacet ||
-									 xsf is XmlSchemaEnumerationFacet ||
-									 xsf is XmlSchemaWhiteSpaceFacet);
+					 return ((xsf.ThisFacet & listFacets) != 0);
 				 }
 
 				 XmlSchemaSimpleTypeUnion stu = st as XmlSchemaSimpleTypeUnion;
@@ -140,19 +150,45 @@ namespace System.Xml.Schema
 			return false;
 		}
 		
+		
+	
 		[MonoTODO]
 		internal override int Validate(ValidationEventHandler h, XmlSchema schema)
 		{
-			NumberStyles lengthStyle = NumberStyles.Integer;
 			
 			if (IsValidated (schema.ValidationId))
 				return errorCount;
 
 			this.ValidateActualType (baseType, baseTypeName, h, schema);
 
+			
+			lengthFacet = maxLengthFacet = minLengthFacet = fractionDigitsFacet = totalDigitsFacet = -1;
+			
+			XmlSchemaSimpleTypeRestriction baseSTR = null; 
+
+			if (actualBaseSchemaType is XmlSchemaSimpleType) {
+				XmlSchemaSimpleTypeContent st = ((XmlSchemaSimpleType)actualBaseSchemaType).Content as XmlSchemaSimpleTypeContent;
+				baseSTR = st as XmlSchemaSimpleTypeRestriction;
+			}
+			
+				
+			if (baseSTR != null) {
+				fixedFacets = baseSTR.fixedFacets;
+				lengthFacet = baseSTR.lengthFacet;
+				maxLengthFacet = baseSTR.maxLengthFacet;
+				minLengthFacet = baseSTR.minLengthFacet;
+				fractionDigitsFacet = baseSTR.fractionDigitsFacet;
+				totalDigitsFacet = baseSTR.totalDigitsFacet;
+				maxInclusiveFacet = baseSTR.maxInclusiveFacet;
+				maxExclusiveFacet = baseSTR.maxExclusiveFacet;
+				minInclusiveFacet = baseSTR.minInclusiveFacet;
+				minExclusiveFacet = baseSTR.minExclusiveFacet;
+			}
+			
 			enumarationFacetValues = patternFacetValues = null;
 			rexPatterns = null;
-			lengthFacet = maxLengthFacet = minLengthFacet = fractionDigitsFacet = totalDigitsFacet = -1;
+			
+			XmlSchemaFacet.Facet facetsDefined = XmlSchemaFacet.Facet.None; 
 
 			ArrayList enums = null;
 			ArrayList patterns = null;
@@ -161,10 +197,17 @@ namespace System.Xml.Schema
 				XmlSchemaFacet facet = facets[i] as XmlSchemaFacet;
 				if (facet != null) {
 					if (!IsAllowedFacet(facet)) {
-						facet.error(h, facet +" is not a valid facet for this type");
+						facet.error(h, facet.ThisFacet +" is not a valid facet for this type");
 						continue;
 					}
 				}
+				else {
+					// FIXME: Not an XmlSchemaFacet, should we complain here?
+					// Definately not worth seeing what sort of facet it is, as
+					// it isn't any of them.
+					continue;
+				}
+
 				
 				XmlSchemaEnumerationFacet ef = facets [i] as XmlSchemaEnumerationFacet;
 				if (ef != null) {
@@ -180,85 +223,295 @@ namespace System.Xml.Schema
 					patterns.Add (pf.Value);
 					continue;
 				}
-				XmlSchemaLengthFacet lf = facets [i] as XmlSchemaLengthFacet;
+				
+				// Put this test here, as pattern and enumeration 
+				// can occur multiple times.
+				if ( (facetsDefined & facet.ThisFacet) !=0) {
+					facet.error (h, "This is a duplicate '" + facet.ThisFacet + "' facet.");
+					continue;
+				}
+				else {
+					facetsDefined |= facet.ThisFacet; 
+				}
+
+				
+				
+
+				
+				if (facet is XmlSchemaLengthFacet) {
+					checkLengthFacet((XmlSchemaLengthFacet)facet, facetsDefined, h);
+				}
+				else if (facet is XmlSchemaMaxLengthFacet) {
+					checkMaxLengthFacet((XmlSchemaMaxLengthFacet)facet, facetsDefined, h);
+				}
+				else if (facet is XmlSchemaMinLengthFacet) {
+					checkMinLengthFacet((XmlSchemaMinLengthFacet)facet, facetsDefined, h);
+				}
+				
+				else if (facet is XmlSchemaMinInclusiveFacet) {
+					checkMinMaxFacet((XmlSchemaMinInclusiveFacet)facet, ref minInclusiveFacet, h);
+				}
+				else if (facet is XmlSchemaMaxInclusiveFacet) {
+					checkMinMaxFacet((XmlSchemaMaxInclusiveFacet)facet, ref maxInclusiveFacet, h);
+				}
+				else if (facet is XmlSchemaMinExclusiveFacet) {
+					checkMinMaxFacet((XmlSchemaMinExclusiveFacet)facet, ref minExclusiveFacet, h);
+				}
+				else if (facet is XmlSchemaMaxExclusiveFacet) {
+					checkMinMaxFacet((XmlSchemaMaxExclusiveFacet)facet, ref maxExclusiveFacet, h);
+				}
+				else if (facet is XmlSchemaFractionDigitsFacet) {
+					checkFractionDigitsFacet((XmlSchemaFractionDigitsFacet)facet, h);
+				}
+				else if (facet is XmlSchemaTotalDigitsFacet) {
+					checkTotalDigitsFacet((XmlSchemaTotalDigitsFacet)facet, h);
+				}
+
+				if (facet.IsFixed) {
+					fixedFacets |= facet.ThisFacet;
+				}
+				
+			 
+			}
+			if (enums != null)
+				this.enumarationFacetValues = enums.ToArray (typeof (string)) as string [];
+			if (patterns != null) {
+				this.patternFacetValues = patterns.ToArray (typeof (string)) as string [];
+				this.rexPatterns = new Regex [patterns.Count];
+				for (int i = 0; i < patternFacetValues.Length; i++) {
+					try {
+						Regex rex = new Regex (patternFacetValues [i]);
+						rexPatterns [i] = rex;
+					} catch (Exception ex) {
+						error (h, "Invalid regular expression pattern was specified.", ex);
+					}
+				}
+				
+				
+			
+			}
+
+			ValidationId = schema.ValidationId;
+		 /* 
+				Console.WriteLine("Facets:\n defined\t{10}\n fixed\t{0}\n length\t{1}\n maxLen\t{2}\n minLen\t{3}\n " +
+													"frac\t{4}\n tot\t{5}\n maxI\t{6}\n maxE\t{7}\n minI\t{8}\n minE\t{9}\n", 
+						fixedFacets , 
+						lengthFacet, 
+						maxLengthFacet ,
+						minLengthFacet ,
+						fractionDigitsFacet ,
+						totalDigitsFacet ,
+						maxInclusiveFacet ,
+						maxExclusiveFacet ,
+						minInclusiveFacet ,
+						minExclusiveFacet , 
+						facetsDefined);
+*/
+			return errorCount;
+		}
+
+
+		private void checkTotalDigitsFacet (XmlSchemaTotalDigitsFacet totf, 
+																				ValidationEventHandler h) {
+			if (totf != null) {
+			/* totalDigits is the maximum number of digits in values of datatypes
+			 * ·derived· from decimal. The value of totalDigits ·must· be a
+			 * positiveInteger. */
+				try {
+					decimal newTotalDigits = decimal.Parse (totf.Value.Trim (), lengthStyle);
+					if (newTotalDigits <= 0) 
+						totf.error(h, String.Format("The value '{0}' is an invalid totalDigits value", newTotalDigits));
+					// Valid restriction
+					if ((totalDigitsFacet > 0) && (newTotalDigits > totalDigitsFacet)) {
+						totf.error(h, String.Format("The value '{0}' is not a valid restriction of the base totalDigits facet '{1}'", newTotalDigits, totalDigitsFacet));
+					}
+					totalDigitsFacet = newTotalDigits;
+				}
+				catch (FormatException ) {
+					totf.error(h, String.Format("The value '{0}' is an invalid totalDigits facet specification", totf.Value.Trim () ));
+				}
+			}
+		}
+
+		
+		private void checkFractionDigitsFacet (XmlSchemaFractionDigitsFacet fracf, 
+																					 ValidationEventHandler h) {
+
+			if (fracf != null) {
+				try {
+					decimal newFractionDigits = decimal.Parse (fracf.Value.Trim (), lengthStyle);
+					if (newFractionDigits< 0) 
+						fracf.error(h, String.Format("The value '{0}' is an invalid fractionDigits value", newFractionDigits));
+					
+					if ((fractionDigitsFacet >= 0) && (newFractionDigits > fractionDigitsFacet)) {
+						fracf.error(h, String.Format("The value '{0}' is not a valid restriction of the base fractionDigits facet '{1}'", newFractionDigits, fractionDigitsFacet));
+					}
+					fractionDigitsFacet = newFractionDigits;
+				}
+				catch (FormatException ) {
+					fracf.error(h, String.Format("The value '{0}' is an invalid fractionDigits facet specification", fracf.Value.Trim () ));
+				}
+			}
+
+		}
+ 
+		
+		private void checkMinMaxFacet(XmlSchemaFacet facet, 
+																		ref object baseFacet,
+																		ValidationEventHandler h) { 
+// Is it a valid instance of the base type.
+		 object newValue = ValidateValueWithDatatype(facet.Value);
+		 if (newValue != null) {
+// Is the base fixed - if so is it the same
+			 if (((fixedFacets & facet.ThisFacet) != 0)  && (baseFacet != null)){
+				 XsdAnySimpleType dt = getDatatype();
+				 if (dt.Compare (newValue, baseFacet) != XsdOrdering.Equal) {
+					 facet.error (h, 
+							 String.Format("{0} is not the same as fixed parent {1} facet.", 
+										 facet.Value, facet.ThisFacet));
+				 }
+			 }
+			 baseFacet = newValue;
+		 }
+		 else {
+			 facet.error(h, 
+					 String.Format("The value '{0}' is not valid against the base type.", facet.Value));
+		 }
+		}
+		
+		
+
+		private void checkLengthFacet(XmlSchemaLengthFacet lf,	
+																	XmlSchemaFacet.Facet facetsDefined, 
+																	ValidationEventHandler h) {
 				if (lf != null) {
 					try {
-						if (minLengthFacet >=0 || maxLengthFacet>=0) 
+					if ((facetsDefined & (XmlSchemaFacet.Facet.minLength | XmlSchemaFacet.Facet.maxLength)) != 0)  
 							lf.error(h, "It is an error for both length and minLength or maxLength to be present.");
-						if (lengthFacet >= 0)
-							lf.error (h, "There already length facet exists.");
 						else {
 							lengthFacet = decimal.Parse (lf.Value.Trim (), lengthStyle);
+						/* TODO: Check that it is between inherited max/min lengths */
 							if (lengthFacet < 0) 
 								lf.error(h, "The value '" + lengthFacet + "' is an invalid length");
 						}
-					} catch (Exception) { // FIXME: better catch ;-(
+				} catch (FormatException) { // FIXME: better catch ;-(
 						lf.error (h, "The value '" + lf.Value + "' is an invalid length facet specification");
 					}
-					continue;
 				}
-				XmlSchemaMaxLengthFacet maxlf = facets [i] as XmlSchemaMaxLengthFacet;
+		}
+
+		private void checkMaxLengthFacet(XmlSchemaMaxLengthFacet maxlf, 
+																		 XmlSchemaFacet.Facet facetsDefined,
+																		 ValidationEventHandler h) {
 				if (maxlf != null) {
 					try {
-						if (lengthFacet >=0) 
+					if ((facetsDefined & XmlSchemaFacet.Facet.length) != 0) 
 							maxlf.error(h, "It is an error for both length and minLength or maxLength to be present.");
-						if (maxLengthFacet >= 0)
-							maxlf.error (h, "There already maxLength facet exists.");
 						else {
-							maxLengthFacet = decimal.Parse (maxlf.Value.Trim (), lengthStyle);
+						decimal newMaxLengthFacet = decimal.Parse (maxlf.Value.Trim (), lengthStyle);
+						
+						if (((fixedFacets & XmlSchemaFacet.Facet.maxLength)!=0) && (newMaxLengthFacet != maxLengthFacet)) 
+							maxlf.error(h, String.Format("The value '{0}' is not the same as the fixed value '{1}' on the base type", maxlf.Value.Trim (), maxLengthFacet));
+						if ((maxLengthFacet >0) && (newMaxLengthFacet > maxLengthFacet)) 
+							maxlf.error(h, String.Format("The value '{0}' is not a valid restriction of the value '{1}' on the base maxLength facet", maxlf.Value.Trim (), maxLengthFacet));
+						else
+							maxLengthFacet = newMaxLengthFacet;
 							if (maxLengthFacet < 0) 
 								maxlf.error(h, "The value '" + maxLengthFacet + "' is an invalid maxLength");
 							if (minLengthFacet >=0 && minLengthFacet > maxLengthFacet)
 								maxlf.error(h, "minLength is greater than maxLength.");
 						}
 
-
-					} catch (Exception) { // FIXME: better catch ;-(
+				} catch (FormatException) { 
 						maxlf.error (h, "The value '" + maxlf.Value+ "' is an invalid maxLength facet specification");
 					}
-					continue;
 				}
-				XmlSchemaMinLengthFacet minlf = facets [i] as XmlSchemaMinLengthFacet;
+		}
+
+		private void checkMinLengthFacet(XmlSchemaMinLengthFacet minlf, 
+																		 XmlSchemaFacet.Facet facetsDefined,
+																		 ValidationEventHandler h) {
 				if (minlf != null) {
 					try {
 						if (lengthFacet >=0) 
 							minlf.error(h, "It is an error for both length and minLength or maxLength to be present.");
-						if (minLengthFacet >= 0)
-							minlf.error (h, "There already minLength facet exists.");
 						else {
-							minLengthFacet = decimal.Parse (minlf.Value.Trim (), lengthStyle);
+						decimal newMinLengthFacet = decimal.Parse (minlf.Value.Trim (), lengthStyle);
+						
+						if (((fixedFacets & XmlSchemaFacet.Facet.minLength)!=0) && (newMinLengthFacet != minLengthFacet)) 
+							minlf.error(h, String.Format("The value '{0}' is not the same as the fixed value '{1}' on the base type", minlf.Value.Trim (), minLengthFacet));
+						if (newMinLengthFacet < minLengthFacet) 
+							minlf.error(h, String.Format("The value '{0}' is not a valid restriction of the value '{1}' on the base minLength facet", minlf.Value.Trim (), minLengthFacet));
+						else
+							minLengthFacet = newMinLengthFacet;
 							if (minLengthFacet < 0) 
 								minlf.error(h, "The value '" + minLengthFacet + "' is an invalid minLength");
 							if (maxLengthFacet >=0 && minLengthFacet > maxLengthFacet)
 								minlf.error(h, "minLength is greater than maxLength.");
 						}
-					} catch (Exception) { // FIXME: better catch ;-(
+				} catch (FormatException) {
 						minlf.error (h, "The value '" + minlf.Value + "' is an invalid minLength facet specification");
 					}
-					continue;
 				}
 			}
-			if (enums != null)
-				this.enumarationFacetValues = enums.ToArray (typeof (string)) as string [];
-			if (patterns != null) {
-				this.patternFacetValues = patterns.ToArray (typeof (string)) as string [];
-				this.rexPatterns = new Regex [patterns.Count];
-				for (int i = 0; i < patternFacetValues.Length; i++) {
+
+
+		private XsdAnySimpleType getDatatype() {
+			XsdAnySimpleType ast = actualBaseSchemaType as XsdAnySimpleType;
+			if (ast != null) {
+				// Based directly on an xsd type 
+				return ast;
+			}
+			XmlSchemaSimpleTypeContent st = ((XmlSchemaSimpleType)actualBaseSchemaType).Content as XmlSchemaSimpleTypeContent;
+			
+			if (st is XmlSchemaSimpleTypeRestriction) {
+				return ((XmlSchemaSimpleTypeRestriction)st).getDatatype();
+			}
+			else if ((st is XmlSchemaSimpleTypeList) ||
+							 (st is XmlSchemaSimpleTypeUnion)) {
+				return null;
+			}
+			return null;
+		}
+
+		
+		private object ValidateValueWithDatatype(string value) {
+			XsdAnySimpleType dt = getDatatype();
+			object ret = null;
+			//		Console.WriteLine("DT: " + dt);
+			if (dt != null) {
 					try {
-						Regex rex = new Regex (patternFacetValues [i]);
-						rexPatterns [i] = rex;
-					} catch (Exception ex) {
-						error (h, "Invalid regular expression pattern was specified.", ex);
+					/* I think we can parse null here, as the types 
+					 * that use the nametable and nsmgr are ones that 
+					 * we don't need to parse here.
+					 */ 
+					ret = dt.ParseValue(value, null, null);
+				//	Console.WriteLine("Ret: " + ret);
+					// If we are based on something with facets, check that we are valid
+					if (actualBaseSchemaType is XmlSchemaSimpleType) {
+						XmlSchemaSimpleTypeContent st = ((XmlSchemaSimpleType)actualBaseSchemaType).Content as XmlSchemaSimpleTypeContent;
+						if (st is XmlSchemaSimpleTypeRestriction) {
+							if (((XmlSchemaSimpleTypeRestriction)st).ValidateValueWithFacets(value, null)) {
+								return ret;
+							} else {
+								return null;
 					}
 				}
 			}
 
-			ValidationId = schema.ValidationId;
-			return errorCount;
+				}catch (Exception e) {
+					return null;
+				}
+			}
+			return ret;
 		}
 
 		internal bool ValidateValueWithFacets (string value, XmlNameTable nt)
 		{
+			/*
+			 * FIXME: Shouldn't this be recursing more? What if this is a 
+			 * restriction of a restriction of a list type?
+			 */
 			XmlSchemaSimpleType baseST = this.ActualBaseSchemaType as XmlSchemaSimpleType;
 			XmlSchemaSimpleTypeList listType = baseST != null ? baseST.Content as XmlSchemaSimpleTypeList : null;
 
@@ -306,6 +559,7 @@ namespace System.Xml.Schema
 			// : minLength
 			if (minLengthFacet >= 0 && list.Length < minLengthFacet)
 					return false;
+			
 			return true;
 		}
 
@@ -329,6 +583,12 @@ namespace System.Xml.Schema
 				if (!matched)
 					return false;
 			}
+			
+			// TODO: Need to skip length tests for 
+			// types derived from QName or NOTATION
+			// see errata: E2-36 Clarification
+			
+						
 			// numeric
 			// : length
 			if (lengthFacet >= 0 && value.Length != lengthFacet)
@@ -340,7 +600,64 @@ namespace System.Xml.Schema
 			if (minLengthFacet >= 0 && value.Length < minLengthFacet)
 					return false;
 
-			// TODO: fractionDigits and totalDigits
+			if ((totalDigitsFacet >=0) || (fractionDigitsFacet >=0)) {
+				String newValue = value.Trim(new Char [] { '+', '-', '0', '.' });
+				int fractionDigits = 0;
+				int totalDigits = newValue.Length;
+				int point = newValue.IndexOf(".");
+				if (point != -1) {
+					totalDigits -= 1;
+					fractionDigits = newValue.Length - point -1; 
+				} 
+				if ((totalDigitsFacet >=0) && (totalDigits > totalDigitsFacet)) 
+					return false;
+				if ((fractionDigitsFacet >=0) && (fractionDigits > fractionDigitsFacet)) 
+					return false;
+			}
+			
+			if ((maxInclusiveFacet != null) ||
+					(maxExclusiveFacet != null) ||
+					(minInclusiveFacet != null) ||
+					(minExclusiveFacet != null)) { 
+				XsdAnySimpleType dt = getDatatype ();
+				if (dt != null) {
+					object parsed;
+					try {
+						parsed = dt.ParseValue (value, nt, null);
+					} catch (OverflowException ) {
+						/* This appears to be what .NET does */
+						return false ;
+					} catch (FormatException ) {
+						/* This appears to be what .NET does */
+						return false ;
+					}
+					
+					if (maxInclusiveFacet != null) {
+						XsdOrdering result = dt.Compare (parsed, maxInclusiveFacet);
+						if ((result != XsdOrdering.LessThan) &&
+								(result != XsdOrdering.Equal)) 
+							return false;
+					}
+					if (maxExclusiveFacet != null) {
+					
+						XsdOrdering result = dt.Compare (parsed, maxExclusiveFacet);
+						if (result != XsdOrdering.LessThan) 
+							return false;
+					}
+					if (minInclusiveFacet != null) {
+						XsdOrdering result = dt.Compare (parsed, minInclusiveFacet);
+						if ((result != XsdOrdering.GreaterThan) &&
+								(result != XsdOrdering.Equal)) 
+							return false;
+					}
+					if (minExclusiveFacet != null) {
+						XsdOrdering result = dt.Compare (parsed, minExclusiveFacet);
+						if (result != XsdOrdering.GreaterThan) 
+							return false;
+					}
+
+				}
+			}
 
 			// all passed
 			return true;

+ 5 - 0
mcs/class/System.XML/System.Xml.Schema/XmlSchemaTotalDigitsFacet.cs

@@ -15,6 +15,11 @@ namespace System.Xml.Schema
 		public XmlSchemaTotalDigitsFacet()
 		{
 		}
+			
+		internal override Facet ThisFacet { 
+			get { return Facet.totalDigits;}
+		}
+	
 		//<totalDigits
 		//  fixed = boolean : false
 		//  id = ID

+ 5 - 0
mcs/class/System.XML/System.Xml.Schema/XmlSchemaWhiteSpaceFacet.cs

@@ -15,6 +15,11 @@ namespace System.Xml.Schema
 		public XmlSchemaWhiteSpaceFacet()
 		{
 		}
+			
+		internal override Facet ThisFacet { 
+			get { return Facet.whiteSpace;}
+		}
+	
 		//	<whiteSpace
 		//	fixed = boolean : false
 		//	id = ID