// // System.Xml.Schema.XmlSchemaElement.cs // // Authors: // Dwivedi, Ajay kumar Adwiv@Yahoo.com // Enomoto, Atsushi ginga@kit.hi-ho.ne.jp // // // 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.Xml; using System.Xml.Serialization; using System.ComponentModel; namespace System.Xml.Schema { /// /// Summary description for XmlSchemaElement. /// public class XmlSchemaElement : XmlSchemaParticle { private XmlSchemaDerivationMethod block; private XmlSchemaObjectCollection constraints; private string defaultValue; private object elementType; #if NET_2_0 private XmlSchemaType elementSchemaType; #endif private XmlSchemaDerivationMethod final; private string fixedValue; private XmlSchemaForm form; private bool isAbstract; private bool isNillable; private string name; private XmlQualifiedName refName; private XmlSchemaType schemaType; private XmlQualifiedName schemaTypeName; private XmlQualifiedName substitutionGroup; // Post compilation items. XmlSchema schema; internal bool parentIsSchema = false; private XmlQualifiedName qName; private XmlSchemaDerivationMethod blockResolved; private XmlSchemaDerivationMethod finalResolved; // private XmlSchemaParticle substChoice; private XmlSchemaElement referencedElement; private ArrayList substitutingElements = new ArrayList (); private XmlSchemaElement substitutionGroupElement; private bool actualIsAbstract; private bool actualIsNillable; private string validatedDefaultValue; private string validatedFixedValue; const string xmlname = "element"; public XmlSchemaElement() { block = XmlSchemaDerivationMethod.None; final = XmlSchemaDerivationMethod.None; constraints = new XmlSchemaObjectCollection(); refName = XmlQualifiedName.Empty; schemaTypeName = XmlQualifiedName.Empty; substitutionGroup = XmlQualifiedName.Empty; InitPostCompileInformations (); } private void InitPostCompileInformations () { qName = XmlQualifiedName.Empty; schema = null; // parentIsSchema = false; ... it is set in Schema's Compile() blockResolved = XmlSchemaDerivationMethod.None; finalResolved = XmlSchemaDerivationMethod.None; // substChoice = null; referencedElement = null; substitutingElements.Clear (); substitutionGroupElement = null; actualIsAbstract = false; actualIsNillable = false; validatedDefaultValue = null; validatedFixedValue = null; } #region Attributes [DefaultValue(false)] [System.Xml.Serialization.XmlAttribute("abstract")] public bool IsAbstract { get{ return isAbstract; } set{ isAbstract = value; } } [DefaultValue(XmlSchemaDerivationMethod.None)] [System.Xml.Serialization.XmlAttribute("block")] public XmlSchemaDerivationMethod Block { get{ return block; } set{ block = value; } } [DefaultValue(null)] [System.Xml.Serialization.XmlAttribute("default")] public string DefaultValue { get{ return defaultValue; } set{ defaultValue = value; } } [DefaultValue(XmlSchemaDerivationMethod.None)] [System.Xml.Serialization.XmlAttribute("final")] public XmlSchemaDerivationMethod Final { get{ return final; } set{ final = value; } } [DefaultValue(null)] [System.Xml.Serialization.XmlAttribute("fixed")] public string FixedValue { get{ return fixedValue; } set{ fixedValue = value; } } [DefaultValue(XmlSchemaForm.None)] [System.Xml.Serialization.XmlAttribute("form")] public XmlSchemaForm Form { get{ return form; } set{ form = value; } } [DefaultValue("")] [System.Xml.Serialization.XmlAttribute("name")] public string Name { get{ return name; } set{ name = value; } } [DefaultValue(false)] [System.Xml.Serialization.XmlAttribute("nillable")] public bool IsNillable { get{ return isNillable; } set{ isNillable = value; } } [System.Xml.Serialization.XmlAttribute("ref")] public XmlQualifiedName RefName { get{ return refName; } set{ refName = value;} } [System.Xml.Serialization.XmlAttribute("substitutionGroup")] public XmlQualifiedName SubstitutionGroup { get{ return substitutionGroup; } set{ substitutionGroup = value; } } [System.Xml.Serialization.XmlAttribute("type")] public XmlQualifiedName SchemaTypeName { get{ return schemaTypeName; } set{ schemaTypeName = value; } } #endregion #region Elements [XmlElement("simpleType",typeof(XmlSchemaSimpleType))] [XmlElement("complexType",typeof(XmlSchemaComplexType))] public XmlSchemaType SchemaType { get{ return schemaType; } set{ schemaType = value; } } [XmlElement("unique",typeof(XmlSchemaUnique))] [XmlElement("key",typeof(XmlSchemaKey))] [XmlElement("keyref",typeof(XmlSchemaKeyref))] public XmlSchemaObjectCollection Constraints { get{ return constraints; } } #endregion #region Post Compilation Schema Info [XmlIgnore] public XmlQualifiedName QualifiedName { get{ return qName; } } [XmlIgnore] #if NET_2_0 [Obsolete] #endif public object ElementType { get { if (referencedElement != null) return referencedElement.ElementType; else return elementType; } } #if NET_2_0 [XmlIgnore] public XmlSchemaType ElementSchemaType { get { if (referencedElement != null) return referencedElement.ElementSchemaType; else return elementSchemaType; } } #endif [XmlIgnore] public XmlSchemaDerivationMethod BlockResolved { get{ if (referencedElement != null) return referencedElement.BlockResolved; else return blockResolved; } } [XmlIgnore] public XmlSchemaDerivationMethod FinalResolved { get{ if (referencedElement != null) return referencedElement.FinalResolved; else return finalResolved; } } internal bool ActualIsNillable { get { if (referencedElement != null) return referencedElement.ActualIsNillable; else return actualIsNillable; } } internal bool ActualIsAbstract { get { if (referencedElement != null) return referencedElement.ActualIsAbstract; else return actualIsAbstract; } } // Post compilation default value (normalized) internal string ValidatedDefaultValue { get{ if (referencedElement != null) return referencedElement.ValidatedDefaultValue; else return validatedDefaultValue; } } // Post compilation fixed value (normalized) internal string ValidatedFixedValue { get{ if (referencedElement != null) return referencedElement.ValidatedFixedValue; else return validatedFixedValue; } } internal ArrayList SubstitutingElements { get { if (referencedElement != null) return referencedElement.SubstitutingElements; else return this.substitutingElements; } } internal XmlSchemaElement SubstitutionGroupElement { get { if (referencedElement != null) return referencedElement.SubstitutionGroupElement; else return substitutionGroupElement; } } #endregion internal override void SetParent (XmlSchemaObject parent) { base.SetParent (parent); if (SchemaType != null) SchemaType.SetParent (this); foreach (XmlSchemaObject obj in Constraints) obj.SetParent (this); } /// /// a) If Element has parent as schema: /// 1. name must be present and of type NCName. /// 2. ref must be absent /// 3. form must be absent /// 4. minOccurs must be absent /// 5. maxOccurs must be absent /// b) If Element has parent is not schema and ref is absent /// 1. name must be present and of type NCName. /// 2. if form equals qualified or form is absent and schema's formdefault is qualifed, /// targetNamespace is schema's targetnamespace else empty. /// 3. type and either or are mutually exclusive /// 4. default and fixed must not both be present. /// 5. substitutiongroup must be absent /// 6. final must be absent /// 7. abstract must be absent /// c) if the parent is not schema and ref is set /// 1. name must not be present /// 2. all of ,, , , , nillable, /// default, fixed, form, block and type, must be absent. /// 3. substitutiongroup is prohibited /// 4. final is prohibited /// 5. abstract is prohibited /// 6. default and fixed must not both be present.(Actually both are absent) /// internal override int Compile(ValidationEventHandler h, XmlSchema schema) { // If this is already compiled this time, simply skip. if (CompilationId == schema.CompilationId) return 0; InitPostCompileInformations (); this.schema = schema; if(this.defaultValue != null && this.fixedValue != null) error(h,"both default and fixed can't be present"); if(parentIsSchema || isRedefineChild) { if(this.refName != null && !RefName.IsEmpty) error(h,"ref must be absent"); if(this.name == null) //b1 error(h,"Required attribute name must be present"); else if(!XmlSchemaUtil.CheckNCName(this.name)) // b1.2 error(h,"attribute name must be NCName"); else this.qName = new XmlQualifiedName (this.name, AncestorSchema.TargetNamespace); if(form != XmlSchemaForm.None) error(h,"form must be absent"); if(MinOccursString != null) error(h,"minOccurs must be absent"); if(MaxOccursString != null) error(h,"maxOccurs must be absent"); XmlSchemaDerivationMethod allfinal = (XmlSchemaDerivationMethod.Extension | XmlSchemaDerivationMethod.Restriction); if(final == XmlSchemaDerivationMethod.All) finalResolved = allfinal; else if(final == XmlSchemaDerivationMethod.None) finalResolved = XmlSchemaDerivationMethod.Empty; else { // if((final & ~allfinal) != 0) if ((final | XmlSchemaUtil.FinalAllowed) != XmlSchemaUtil.FinalAllowed) error (h,"some values for final are invalid in this context"); finalResolved = final & allfinal; } if(schemaType != null && schemaTypeName != null && !schemaTypeName.IsEmpty) { error(h,"both schemaType and content can't be present"); } //Even if both are present, read both of them. if(schemaType != null) { if(schemaType is XmlSchemaSimpleType) { errorCount += ((XmlSchemaSimpleType)schemaType).Compile(h,schema); } else if(schemaType is XmlSchemaComplexType) { errorCount += ((XmlSchemaComplexType)schemaType).Compile(h,schema); } else error(h,"only simpletype or complextype is allowed"); } if(schemaTypeName != null && !schemaTypeName.IsEmpty) { if(!XmlSchemaUtil.CheckQName(SchemaTypeName)) error(h,"SchemaTypeName must be an XmlQualifiedName"); } if(SubstitutionGroup != null && !SubstitutionGroup.IsEmpty) { if(!XmlSchemaUtil.CheckQName(SubstitutionGroup)) error(h,"SubstitutionGroup must be a valid XmlQualifiedName"); } foreach(XmlSchemaObject obj in constraints) { if(obj is XmlSchemaUnique) errorCount += ((XmlSchemaUnique)obj).Compile(h,schema); else if(obj is XmlSchemaKey) errorCount += ((XmlSchemaKey)obj).Compile(h,schema); else if(obj is XmlSchemaKeyref) errorCount += ((XmlSchemaKeyref)obj).Compile(h,schema); } } else { if(substitutionGroup != null && !substitutionGroup.IsEmpty) error(h,"substitutionGroup must be absent"); if(final != XmlSchemaDerivationMethod.None) error(h,"final must be absent"); CompileOccurence (h, schema); if(refName == null || RefName.IsEmpty) { string targetNamespace = String.Empty; if(form == XmlSchemaForm.Qualified || (form == XmlSchemaForm.None && AncestorSchema.ElementFormDefault == XmlSchemaForm.Qualified)) targetNamespace = AncestorSchema.TargetNamespace; if(this.name == null) //b1 error(h,"Required attribute name must be present"); else if(!XmlSchemaUtil.CheckNCName(this.name)) // b1.2 error(h,"attribute name must be NCName"); else this.qName = new XmlQualifiedName(this.name, targetNamespace); if(schemaType != null && schemaTypeName != null && !schemaTypeName.IsEmpty) { error(h,"both schemaType and content can't be present"); } //Even if both are present, read both of them. if(schemaType != null) { if(schemaType is XmlSchemaSimpleType) { errorCount += ((XmlSchemaSimpleType)schemaType).Compile(h,schema); } else if(schemaType is XmlSchemaComplexType) { errorCount += ((XmlSchemaComplexType)schemaType).Compile(h,schema); } else error(h,"only simpletype or complextype is allowed"); } if(schemaTypeName != null && !schemaTypeName.IsEmpty) { if(!XmlSchemaUtil.CheckQName(SchemaTypeName)) error(h,"SchemaTypeName must be an XmlQualifiedName"); } if(SubstitutionGroup != null && !SubstitutionGroup.IsEmpty) { if(!XmlSchemaUtil.CheckQName(SubstitutionGroup)) error(h,"SubstitutionGroup must be a valid XmlQualifiedName"); } foreach(XmlSchemaObject obj in constraints) { if(obj is XmlSchemaUnique) errorCount += ((XmlSchemaUnique)obj).Compile(h,schema); else if(obj is XmlSchemaKey) errorCount += ((XmlSchemaKey)obj).Compile(h,schema); else if(obj is XmlSchemaKeyref) errorCount += ((XmlSchemaKeyref)obj).Compile(h,schema); } } else { if(!XmlSchemaUtil.CheckQName(RefName)) error(h,"RefName must be a XmlQualifiedName"); if(name != null) error(h,"name must not be present when ref is present"); if(Constraints.Count != 0) error(h,"key, keyref and unique must be absent"); if(isNillable) error(h,"nillable must be absent"); if(defaultValue != null) error(h,"default must be absent"); if(fixedValue != null) error(h,"fixed must be null"); if(form != XmlSchemaForm.None) error(h,"form must be absent"); if(block != XmlSchemaDerivationMethod.None) error(h,"block must be absent"); if(schemaTypeName != null && !schemaTypeName.IsEmpty) error(h,"type must be absent"); if(SchemaType != null) error(h,"simpleType or complexType must be absent"); qName = RefName; } } switch (block) { case XmlSchemaDerivationMethod.All: blockResolved = XmlSchemaDerivationMethod.All; break; case XmlSchemaDerivationMethod.None: blockResolved = XmlSchemaDerivationMethod.Empty; break; default: if ((block | XmlSchemaUtil.ElementBlockAllowed) != XmlSchemaUtil.ElementBlockAllowed) error (h,"Some of the values for block are invalid in this context"); blockResolved = block; break; } if (Constraints != null) { XmlSchemaObjectTable table = new XmlSchemaObjectTable (); foreach (XmlSchemaIdentityConstraint c in Constraints) { XmlSchemaUtil.AddToTable (table, c, c.QualifiedName, h); } } XmlSchemaUtil.CompileID(Id,this,schema.IDCollection,h); this.CompilationId = schema.CompilationId; return errorCount; } // FIXME: Return clone in case when it returns itself internal override XmlSchemaParticle GetOptimizedParticle (bool isTop) { if (OptimizedParticle != null) return OptimizedParticle; if (RefName != null && RefName != XmlQualifiedName.Empty) { referencedElement = schema.FindElement (RefName); } // if (this.referencedElement != null) // OptimizedParticle = referencedElement.GetOptimizedParticle (isTop); // else if (ValidatedMaxOccurs == 0) OptimizedParticle = XmlSchemaParticle.Empty; // Substitution Group else if (SubstitutingElements != null && SubstitutingElements.Count > 0) { XmlSchemaChoice choice = new XmlSchemaChoice (); choice.MinOccurs = MinOccurs; choice.MaxOccurs = MaxOccurs; // substChoice = choice; choice.Compile (null, schema); // compute Validated Min/Max Occurs. XmlSchemaElement item = this.MemberwiseClone () as XmlSchemaElement; item.MinOccurs = 1; item.MaxOccurs = 1; item.substitutionGroupElement = null; item.substitutingElements = null; for (int i = 0; i < SubstitutingElements.Count; i++) { XmlSchemaElement se = SubstitutingElements [i] as XmlSchemaElement; // choice.Items.Add (se); // choice.CompiledItems.Add (se); this.AddSubstElementRecursively (choice.Items, se); this.AddSubstElementRecursively (choice.CompiledItems, se); } if (!choice.Items.Contains (item)) { choice.Items.Add (item); choice.CompiledItems.Add (item); } OptimizedParticle = choice; } else OptimizedParticle = this;//.MemberwiseClone () as XmlSchemaElement; return OptimizedParticle; } private void AddSubstElementRecursively (XmlSchemaObjectCollection col, XmlSchemaElement el) { if (el.SubstitutingElements != null) for (int i = 0; i < el.SubstitutingElements.Count; i++) this.AddSubstElementRecursively (col, el.SubstitutingElements [i] as XmlSchemaElement); if (!col.Contains (el)) col.Add (el); } internal void FillSubstitutionElementInfo () { if (this.substitutionGroupElement != null) return; if (this.SubstitutionGroup != XmlQualifiedName.Empty) { XmlSchemaElement substElem = schema.FindElement (SubstitutionGroup); this.substitutionGroupElement = substElem; if (substElem != null) substElem.substitutingElements.Add (this); } } internal override int Validate(ValidationEventHandler h, XmlSchema schema) { if (IsValidated (schema.CompilationId)) return errorCount; // See XML Schema Structures 3.6 for the complete description. // Element Declaration Properties Correct // 1. = 3.3.1 (modulo 5.3) // 3.3.1: // {annotation} is as is. // {name}, {target namespace}, {scope}, {disallowed substitution}, // {substitution group exclusions} (handled the same as 'disallowed substitution') // and {identity-constraint-definitions} are Compile()d. // {value constraint} is going to be filled in step 2. // actual {nillable}, {abstract} this.actualIsNillable = IsNillable; this.actualIsAbstract = IsAbstract; // Before determining element type, we need to validate substituting element if (this.SubstitutionGroup != XmlQualifiedName.Empty) { XmlSchemaElement substElem = substitutionGroupElement; if (substElem != null) substElem.Validate (h, schema); } // {type} from here XmlSchemaDatatype datatype = null; if (schemaType != null) elementType = schemaType; else if (SchemaTypeName != XmlQualifiedName.Empty) { XmlSchemaType type = schema.FindSchemaType (SchemaTypeName); if (type != null) { type.Validate (h, schema); elementType = type; } else if (SchemaTypeName == XmlSchemaComplexType.AnyTypeName) elementType = XmlSchemaComplexType.AnyType; else if (XmlSchemaUtil.IsBuiltInDatatypeName (SchemaTypeName)) { datatype = XmlSchemaDatatype.FromName (SchemaTypeName); if (datatype == null) error (h, "Invalid schema datatype was specified."); else elementType = datatype; } // otherwise, it might be missing sub components. else if (!schema.IsNamespaceAbsent (SchemaTypeName.Namespace)) error (h, "Referenced element schema type " + SchemaTypeName + " was not found in the corresponding schema."); } else if (RefName != XmlQualifiedName.Empty) { XmlSchemaElement refElem = schema.FindElement (RefName); // If el is null, then it is missing sub components . if (refElem != null) { this.referencedElement = refElem; errorCount += refElem.Validate (h, schema); } // otherwise, it might be missing sub components. else if (!schema.IsNamespaceAbsent (RefName.Namespace)) error (h, "Referenced element " + RefName + " was not found in the corresponding schema."); } // Otherwise if there are substitution group, then the type of the substitution group element. if (referencedElement == null) { if (elementType == null && this.substitutionGroupElement != null) elementType = substitutionGroupElement.ElementType; // Otherwise, the -ur type- definition. if (elementType == null) elementType = XmlSchemaComplexType.AnyType; } XmlSchemaType xsType = elementType as XmlSchemaType; if (xsType != null) { errorCount += xsType.Validate (h, schema); datatype = xsType.Datatype; } // basic {type} is now filled, except for derivation by {substitution group}. // {substitution group affiliation} // 3. subsitution group's type derivation check. if (this.SubstitutionGroup != XmlQualifiedName.Empty) { XmlSchemaElement substElem = schema.FindElement (SubstitutionGroup); // If el is null, then it is missing sub components . if (substElem != null) { XmlSchemaType substSchemaType = substElem.ElementType as XmlSchemaType; if (substSchemaType != null) { // 3.3.6 Properties Correct 3. if ((substElem.FinalResolved & XmlSchemaDerivationMethod.Substitution) != 0) error (h, "Substituted element blocks substitution."); if (xsType != null && (substElem.FinalResolved & xsType.DerivedBy) != 0) error (h, "Invalid derivation was found. Substituted element prohibits this derivation method: " + xsType.DerivedBy + "."); } XmlSchemaComplexType xsComplexType = xsType as XmlSchemaComplexType; if (xsComplexType != null) xsComplexType.ValidateTypeDerivationOK (substElem.ElementType, h, schema); else { XmlSchemaSimpleType xsSimpleType = xsType as XmlSchemaSimpleType; if (xsSimpleType != null) xsSimpleType.ValidateTypeDerivationOK (substElem.ElementType, h, schema, true); } } // otherwise, it might be missing sub components. else if (!schema.IsNamespaceAbsent (SubstitutionGroup.Namespace)) error (h, "Referenced element type " + SubstitutionGroup + " was not found in the corresponding schema."); } // 2. ElementDefaultValid // 4. ID with {value constraint} is prohibited. if (defaultValue != null || fixedValue != null) { ValidateElementDefaultValidImmediate (h, schema); if (datatype != null && // Such situation is basically an error. For ValidationEventHandler. datatype.TokenizedType == XmlTokenizedType.ID) error (h, "Element type is ID, which does not allows default or fixed values."); } // Identity constraints (3.11.3 / 3.11.6) foreach (XmlSchemaIdentityConstraint ident in Constraints) ident.Validate (h, schema); #if NET_2_0 if (elementType != null) { elementSchemaType = elementType as XmlSchemaType; if (elementType == XmlSchemaSimpleType.AnySimpleType) elementSchemaType = XmlSchemaSimpleType.XsAnySimpleType; if (elementSchemaType == null) elementSchemaType = XmlSchemaType.GetBuiltInSimpleType (SchemaTypeName); } #endif ValidationId = schema.ValidationId; return errorCount; } internal override bool ParticleEquals (XmlSchemaParticle other) { XmlSchemaElement element = other as XmlSchemaElement; if (element == null) return false; if (this.ValidatedMaxOccurs != element.ValidatedMaxOccurs || this.ValidatedMinOccurs != element.ValidatedMinOccurs) return false; if (this.QualifiedName != element.QualifiedName || this.ElementType != element.ElementType || this.Constraints.Count != element.Constraints.Count) return false; for (int i = 0; i < this.Constraints.Count; i++) { XmlSchemaIdentityConstraint c1 = Constraints [i] as XmlSchemaIdentityConstraint; XmlSchemaIdentityConstraint c2 = element.Constraints [i] as XmlSchemaIdentityConstraint; if (c1.QualifiedName != c2.QualifiedName || c1.Selector.XPath != c2.Selector.XPath || c1.Fields.Count != c2.Fields.Count) return false; for (int f = 0; f < c1.Fields.Count; f++) { XmlSchemaXPath f1 = c1.Fields [f] as XmlSchemaXPath; XmlSchemaXPath f2 = c2.Fields [f] as XmlSchemaXPath; if (f1.XPath != f2.XPath) return false; } } if (this.BlockResolved != element.BlockResolved || this.FinalResolved != element.FinalResolved || this.ValidatedDefaultValue != element.ValidatedDefaultValue || this.ValidatedFixedValue != element.ValidatedFixedValue) return false; return true; } internal override bool ValidateDerivationByRestriction (XmlSchemaParticle baseParticle, ValidationEventHandler h, XmlSchema schema, bool raiseError) { // element - NameAndTypeOK XmlSchemaElement baseElement = baseParticle as XmlSchemaElement; if (baseElement != null) { return ValidateDerivationByRestrictionNameAndTypeOK (baseElement, h, schema, raiseError); } // any - NSCompat XmlSchemaAny baseAny = baseParticle as XmlSchemaAny; if (baseAny != null) { // NSCompat if (!baseAny.ValidateWildcardAllowsNamespaceName (this.QualifiedName.Namespace, h, schema, raiseError)) return false; return ValidateOccurenceRangeOK (baseAny, h, schema, raiseError); } //* // choice - RecurseAsIfGroup XmlSchemaGroupBase gb = null; if (baseParticle is XmlSchemaSequence) gb = new XmlSchemaSequence (); else if (baseParticle is XmlSchemaChoice) gb = new XmlSchemaChoice (); else if (baseParticle is XmlSchemaAll) gb = new XmlSchemaAll (); if (gb != null) { gb.Items.Add (this); gb.Compile (h, schema); gb.Validate (h, schema); // It looks weird, but here we never think about // _pointlessness_ of this groupbase particle. return gb.ValidateDerivationByRestriction (baseParticle, h, schema, raiseError); } //*/ return true; } private bool ValidateDerivationByRestrictionNameAndTypeOK (XmlSchemaElement baseElement, ValidationEventHandler h, XmlSchema schema, bool raiseError) { // 1. if (this.QualifiedName != baseElement.QualifiedName) { if (raiseError) error (h, "Invalid derivation by restriction of particle was found. Both elements must have the same name."); return false; } // 2. if (this.isNillable && !baseElement.isNillable) { if (raiseError) error (h, "Invalid element derivation by restriction of particle was found. Base element is not nillable and derived type is nillable."); return false; } // 3. if (!ValidateOccurenceRangeOK (baseElement, h, schema, raiseError)) return false; // 4. if (baseElement.ValidatedFixedValue != null && baseElement.ValidatedFixedValue != this.ValidatedFixedValue) { if (raiseError) error (h, "Invalid element derivation by restriction of particle was found. Both fixed value must be the same."); return false; } // 5. TODO: What is "identity constraints subset" ??? // 6. if ((baseElement.BlockResolved | this.BlockResolved) != this.BlockResolved) { if (raiseError) error (h, "Invalid derivation by restriction of particle was found. Derived element must contain all of the base element's block value."); return false; } // 7. if (baseElement.ElementType != null) { XmlSchemaComplexType derivedCType = this.ElementType as XmlSchemaComplexType; if (derivedCType != null) { // FIXME: W3C REC says that it is Type Derivation OK to be check, but // in fact it should be DerivationValid (Restriction, Complex). derivedCType.ValidateDerivationValidRestriction ( baseElement.ElementType as XmlSchemaComplexType, h, schema); derivedCType.ValidateTypeDerivationOK (baseElement.ElementType, h, schema); } else { XmlSchemaSimpleType derivedSType = this.ElementType as XmlSchemaSimpleType; if (derivedSType != null) derivedSType.ValidateTypeDerivationOK (baseElement.ElementType, h, schema, true); else if (baseElement.ElementType != XmlSchemaComplexType.AnyType && baseElement.ElementType != this.ElementType) { if (raiseError) error (h, "Invalid element derivation by restriction of particle was found. Both primitive types differ."); return false; } } } return true; } internal override void CheckRecursion (int depth, ValidationEventHandler h, XmlSchema schema) { XmlSchemaComplexType ct = this.ElementType as XmlSchemaComplexType; if (ct == null || ct.Particle == null) return; ct.Particle.CheckRecursion (depth + 1, h, schema); } internal override void ValidateUniqueParticleAttribution (XmlSchemaObjectTable qnames, ArrayList nsNames, ValidationEventHandler h, XmlSchema schema) { if (qnames.Contains (this.QualifiedName))// && !this.ParticleEquals ((XmlSchemaParticle) qnames [this.QualifiedName])) error (h, "Ambiguous element label was detected: " + this.QualifiedName); else { foreach (XmlSchemaAny any in nsNames) { if (any.ValidatedMaxOccurs == 0) continue; if (any.HasValueAny || any.HasValueLocal && this.QualifiedName.Namespace == "" || any.HasValueOther && this.QualifiedName.Namespace != this.QualifiedName.Namespace || any.HasValueTargetNamespace && this.QualifiedName.Namespace == this.QualifiedName.Namespace) { error (h, "Ambiguous element label which is contained by -any- particle was detected: " + this.QualifiedName); break; } else if (!any.HasValueOther) { bool bad = false; foreach (string ns in any.ResolvedNamespaces) { if (ns == this.QualifiedName.Namespace) { bad = true; break; } } if (bad) { error (h, "Ambiguous element label which is contained by -any- particle was detected: " + this.QualifiedName); break; } } else { if (any.TargetNamespace != this.QualifiedName.Namespace) error (h, String.Format ("Ambiguous element label '{0}' which is contained by -any- particle with ##other value than '{1}' was detected: ", this.QualifiedName.Namespace, any.TargetNamespace)); } } qnames.Add (this.QualifiedName, this); } } internal override void ValidateUniqueTypeAttribution (XmlSchemaObjectTable labels, ValidationEventHandler h, XmlSchema schema) { XmlSchemaElement labeled = labels [this.QualifiedName] as XmlSchemaElement; if (labeled == null) labels.Add (this.QualifiedName, this); else if (labeled.ElementType != this.ElementType) error (h, "Different types are specified on the same named elements in the same sequence. Element name is " + QualifiedName); } // 3.3.6 Element Default Valid (Immediate) private void ValidateElementDefaultValidImmediate (ValidationEventHandler h, XmlSchema schema) { // This presumes that ElementType is already filled. XmlSchemaDatatype datatype = elementType as XmlSchemaDatatype; XmlSchemaSimpleType simpleType = elementType as XmlSchemaSimpleType; if (simpleType != null) datatype = simpleType.Datatype; if (datatype == null) { XmlSchemaComplexType complexType = elementType as XmlSchemaComplexType; switch (complexType.ContentType) { case XmlSchemaContentType.Empty: case XmlSchemaContentType.ElementOnly: error (h, "Element content type must be simple type or mixed."); break; } datatype = XmlSchemaSimpleType.AnySimpleType; } XmlNamespaceManager nsmgr = null; if (datatype.TokenizedType == XmlTokenizedType.QName) { if (this.Namespaces != null) foreach (XmlQualifiedName qname in Namespaces.ToArray ()) { if (nsmgr == null) nsmgr = new XmlNamespaceManager (new NameTable()); nsmgr.AddNamespace (qname.Name, qname.Namespace); } } try { if (defaultValue != null) { validatedDefaultValue = datatype.Normalize (defaultValue); datatype.ParseValue (validatedDefaultValue, null, nsmgr); } } catch (Exception ex) { // FIXME: This is not a good way to handle exception, but // I think there is no remedy for such Framework specification. error (h, "The Element's default value is invalid with respect to its type definition.", ex); } try { if (fixedValue != null) { validatedFixedValue = datatype.Normalize (fixedValue); datatype.ParseValue (validatedFixedValue, null, nsmgr); } } catch (Exception ex) { // FIXME: This is not a good way to handle exception. error (h, "The Element's fixed value is invalid with its type definition.", ex); } } // // Content: (annotation?, ((simpleType | complexType)?, (unique | key | keyref)*)) // internal static XmlSchemaElement Read(XmlSchemaReader reader, ValidationEventHandler h) { XmlSchemaElement element = new XmlSchemaElement(); Exception innerex; reader.MoveToElement(); if(reader.NamespaceURI != XmlSchema.Namespace || reader.LocalName != xmlname) { error(h,"Should not happen :1: XmlSchemaElement.Read, name="+reader.Name,null); reader.Skip(); return null; } element.LineNumber = reader.LineNumber; element.LinePosition = reader.LinePosition; element.SourceUri = reader.BaseURI; while(reader.MoveToNextAttribute()) { if(reader.Name == "abstract") { element.IsAbstract = XmlSchemaUtil.ReadBoolAttribute(reader,out innerex); if(innerex != null) error(h,reader.Value + " is invalid value for abstract",innerex); } else if(reader.Name == "block") { element.block = XmlSchemaUtil.ReadDerivationAttribute(reader,out innerex, "block", XmlSchemaUtil.ElementBlockAllowed); if(innerex != null) error (h,"some invalid values for block attribute were found",innerex); } else if(reader.Name == "default") { element.defaultValue = reader.Value; } else if(reader.Name == "final") { element.Final = XmlSchemaUtil.ReadDerivationAttribute(reader,out innerex, "final", XmlSchemaUtil.FinalAllowed); if(innerex != null) error (h,"some invalid values for final attribute were found",innerex); } else if(reader.Name == "fixed") { element.fixedValue = reader.Value; } else if(reader.Name == "form") { element.form = XmlSchemaUtil.ReadFormAttribute(reader,out innerex); if(innerex != null) error(h,reader.Value + " is an invalid value for form attribute",innerex); } else if(reader.Name == "id") { element.Id = reader.Value; } else if(reader.Name == "maxOccurs") { try { element.MaxOccursString = reader.Value; } catch(Exception e) { error(h,reader.Value + " is an invalid value for maxOccurs",e); } } else if(reader.Name == "minOccurs") { try { element.MinOccursString = reader.Value; } catch(Exception e) { error(h,reader.Value + " is an invalid value for minOccurs",e); } } else if(reader.Name == "name") { element.Name = reader.Value; } else if(reader.Name == "nillable") { element.IsNillable = XmlSchemaUtil.ReadBoolAttribute(reader,out innerex); if(innerex != null) error(h,reader.Value + "is not a valid value for nillable",innerex); } else if(reader.Name == "ref") { element.refName = XmlSchemaUtil.ReadQNameAttribute(reader,out innerex); if(innerex != null) error(h, reader.Value + " is not a valid value for ref attribute",innerex); } else if(reader.Name == "substitutionGroup") { element.substitutionGroup = XmlSchemaUtil.ReadQNameAttribute(reader,out innerex); if(innerex != null) error(h, reader.Value + " is not a valid value for substitutionGroup attribute",innerex); } else if(reader.Name == "type") { element.SchemaTypeName = XmlSchemaUtil.ReadQNameAttribute(reader,out innerex); if(innerex != null) error(h, reader.Value + " is not a valid value for type attribute",innerex); } else if((reader.NamespaceURI == "" && reader.Name != "xmlns") || reader.NamespaceURI == XmlSchema.Namespace) { error(h,reader.Name + " is not a valid attribute for element",null); } else { XmlSchemaUtil.ReadUnhandledAttribute(reader,element); } } reader.MoveToElement(); if(reader.IsEmptyElement) return element; // Content: annotation?, // (simpleType | complexType)?, // (unique | key | keyref)* int level = 1; while(reader.ReadNextElement()) { if(reader.NodeType == XmlNodeType.EndElement) { if(reader.LocalName != xmlname) error(h,"Should not happen :2: XmlSchemaElement.Read, name="+reader.Name,null); break; } if(level <= 1 && reader.LocalName == "annotation") { level = 2; //Only one annotation XmlSchemaAnnotation annotation = XmlSchemaAnnotation.Read(reader,h); if(annotation != null) element.Annotation = annotation; continue; } if(level <= 2) { if(reader.LocalName == "simpleType") { level = 3; XmlSchemaSimpleType simple = XmlSchemaSimpleType.Read(reader,h); if(simple != null) element.SchemaType = simple; continue; } if(reader.LocalName == "complexType") { level = 3; XmlSchemaComplexType complex = XmlSchemaComplexType.Read(reader,h); if(complex != null) { element.SchemaType = complex; } continue; } } if(level <= 3) { if(reader.LocalName == "unique") { level = 3; XmlSchemaUnique unique = XmlSchemaUnique.Read(reader,h); if(unique != null) element.constraints.Add(unique); continue; } else if(reader.LocalName == "key") { level = 3; XmlSchemaKey key = XmlSchemaKey.Read(reader,h); if(key != null) element.constraints.Add(key); continue; } else if(reader.LocalName == "keyref") { level = 3; XmlSchemaKeyref keyref = XmlSchemaKeyref.Read(reader,h); if(keyref != null) element.constraints.Add(keyref); continue; } } reader.RaiseInvalidElementError(); } return element; } } }