1 //------------------------------------------------------------------------------
2 // <copyright file="XmlSchemaComplexType.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
5 // <owner current="true" primary="true">[....]</owner>
6 //------------------------------------------------------------------------------
8 namespace System.Xml.Schema {
10 using System.Collections;
11 using System.ComponentModel;
12 using System.Xml.Serialization;
14 /// <include file='doc\XmlSchemaComplexType.uex' path='docs/doc[@for="XmlSchemaComplexType"]/*' />
16 /// <para>[To be supplied.]</para>
18 public class XmlSchemaComplexType : XmlSchemaType {
19 XmlSchemaDerivationMethod block = XmlSchemaDerivationMethod.None;
21 XmlSchemaContentModel contentModel;
22 XmlSchemaParticle particle;
23 XmlSchemaObjectCollection attributes;
24 XmlSchemaAnyAttribute anyAttribute;
26 XmlSchemaParticle contentTypeParticle = XmlSchemaParticle.Empty;
27 XmlSchemaDerivationMethod blockResolved;
28 XmlSchemaObjectTable localElements;
29 XmlSchemaObjectTable attributeUses;
30 XmlSchemaAnyAttribute attributeWildcard;
32 static XmlSchemaComplexType anyTypeLax;
33 static XmlSchemaComplexType anyTypeSkip;
34 static XmlSchemaComplexType untypedAnyType;
36 //additional info for Partial validation
38 const byte wildCardMask = 0x01;
39 const byte isMixedMask = 0x02;
40 const byte isAbstractMask = 0x04;
41 //const byte dupDeclMask = 0x08;
43 static XmlSchemaComplexType() {
44 anyTypeLax = CreateAnyType(XmlSchemaContentProcessing.Lax);
45 anyTypeSkip = CreateAnyType(XmlSchemaContentProcessing.Skip);
47 // Create xdt:untypedAny
48 untypedAnyType = new XmlSchemaComplexType();
49 untypedAnyType.SetQualifiedName(new XmlQualifiedName("untypedAny", XmlReservedNs.NsXQueryDataType));
50 untypedAnyType.IsMixed = true;
51 untypedAnyType.SetContentTypeParticle(anyTypeLax.ContentTypeParticle);
52 untypedAnyType.SetContentType(XmlSchemaContentType.Mixed);
54 untypedAnyType.ElementDecl = SchemaElementDecl.CreateAnyTypeElementDecl();
55 untypedAnyType.ElementDecl.SchemaType = untypedAnyType;
56 untypedAnyType.ElementDecl.ContentValidator = AnyTypeContentValidator;
60 static XmlSchemaComplexType CreateAnyType(XmlSchemaContentProcessing processContents) {
61 XmlSchemaComplexType localAnyType = new XmlSchemaComplexType();
62 localAnyType.SetQualifiedName(DatatypeImplementation.QnAnyType);
64 XmlSchemaAny anyElement = new XmlSchemaAny();
65 anyElement.MinOccurs = decimal.Zero;
66 anyElement.MaxOccurs = decimal.MaxValue;
68 anyElement.ProcessContents = processContents;
69 anyElement.BuildNamespaceList(null);
70 XmlSchemaSequence seq = new XmlSchemaSequence();
71 seq.Items.Add(anyElement);
73 localAnyType.SetContentTypeParticle(seq);
74 localAnyType.SetContentType(XmlSchemaContentType.Mixed);
76 localAnyType.ElementDecl = SchemaElementDecl.CreateAnyTypeElementDecl();
77 localAnyType.ElementDecl.SchemaType = localAnyType;
79 //Create contentValidator for Any
80 ParticleContentValidator contentValidator = new ParticleContentValidator(XmlSchemaContentType.Mixed);
81 contentValidator.Start();
82 contentValidator.OpenGroup();
83 contentValidator.AddNamespaceList(anyElement.NamespaceList, anyElement);
84 contentValidator.AddStar();
85 contentValidator.CloseGroup();
86 ContentValidator anyContentValidator = contentValidator.Finish(true);
87 localAnyType.ElementDecl.ContentValidator = anyContentValidator;
89 XmlSchemaAnyAttribute anyAttribute = new XmlSchemaAnyAttribute();
90 anyAttribute.ProcessContents = processContents;
91 anyAttribute.BuildNamespaceList(null);
92 localAnyType.SetAttributeWildcard(anyAttribute);
93 localAnyType.ElementDecl.AnyAttribute = anyAttribute;
97 /// <include file='doc\XmlSchemaComplexType.uex' path='docs/doc[@for="XmlSchemaComplexType.XmlSchemaComplexType"]/*' />
99 /// <para>[To be supplied.]</para>
101 public XmlSchemaComplexType() {
106 internal static XmlSchemaComplexType AnyType {
107 get { return anyTypeLax; }
111 internal static XmlSchemaComplexType UntypedAnyType {
112 get { return untypedAnyType; }
116 internal static XmlSchemaComplexType AnyTypeSkip {
117 get { return anyTypeSkip; }
120 internal static ContentValidator AnyTypeContentValidator {
122 return anyTypeLax.ElementDecl.ContentValidator;
125 /// <include file='doc\XmlSchemaComplexType.uex' path='docs/doc[@for="XmlSchemaComplexType.IsAbstract"]/*' />
127 /// <para>[To be supplied.]</para>
129 [XmlAttribute("abstract"), DefaultValue(false)]
130 public bool IsAbstract {
132 return (pvFlags & isAbstractMask) != 0;
136 pvFlags = (byte)(pvFlags | isAbstractMask);
139 pvFlags = (byte)(pvFlags & ~isAbstractMask);
144 /// <include file='doc\XmlSchemaComplexType.uex' path='docs/doc[@for="XmlSchemaComplexType.Block"]/*' />
146 /// <para>[To be supplied.]</para>
148 [XmlAttribute("block"), DefaultValue(XmlSchemaDerivationMethod.None)]
149 public XmlSchemaDerivationMethod Block {
150 get { return block; }
151 set { block = value; }
154 /// <include file='doc\XmlSchemaComplexType.uex' path='docs/doc[@for="XmlSchemaComplexType.IsMixed"]/*' />
156 /// <para>[To be supplied.]</para>
158 [XmlAttribute("mixed"), DefaultValue(false)]
159 public override bool IsMixed {
161 return (pvFlags & isMixedMask) != 0;
165 pvFlags = (byte)(pvFlags | isMixedMask);
168 pvFlags = (byte)(pvFlags & ~isMixedMask);
174 /// <include file='doc\XmlSchemaComplexType.uex' path='docs/doc[@for="XmlSchemaComplexType.ContentModel"]/*' />
176 /// <para>[To be supplied.]</para>
178 [XmlElement("simpleContent", typeof(XmlSchemaSimpleContent)),
179 XmlElement("complexContent", typeof(XmlSchemaComplexContent))]
180 public XmlSchemaContentModel ContentModel {
181 get { return contentModel; }
182 set { contentModel = value; }
185 /// <include file='doc\XmlSchemaComplexType.uex' path='docs/doc[@for="XmlSchemaComplexType.Particle"]/*' />
187 /// <para>[To be supplied.]</para>
189 [XmlElement("group", typeof(XmlSchemaGroupRef)),
190 XmlElement("choice", typeof(XmlSchemaChoice)),
191 XmlElement("all", typeof(XmlSchemaAll)),
192 XmlElement("sequence", typeof(XmlSchemaSequence))]
193 public XmlSchemaParticle Particle {
194 get { return particle; }
195 set { particle = value; }
198 /// <include file='doc\XmlSchemaComplexType.uex' path='docs/doc[@for="XmlSchemaComplexType.Attributes"]/*' />
200 /// <para>[To be supplied.]</para>
202 [XmlElement("attribute", typeof(XmlSchemaAttribute)),
203 XmlElement("attributeGroup", typeof(XmlSchemaAttributeGroupRef))]
204 public XmlSchemaObjectCollection Attributes {
206 if (attributes == null) {
207 attributes = new XmlSchemaObjectCollection();
213 /// <include file='doc\XmlSchemaComplexType.uex' path='docs/doc[@for="XmlSchemaComplexType.AnyAttribute"]/*' />
215 /// <para>[To be supplied.]</para>
217 [XmlElement("anyAttribute")]
218 public XmlSchemaAnyAttribute AnyAttribute {
219 get { return anyAttribute; }
220 set { anyAttribute = value; }
224 /// <include file='doc\XmlSchemaComplexType.uex' path='docs/doc[@for="XmlSchemaComplexType.ContentType"]/*' />
226 /// <para>[To be supplied.]</para>
229 public XmlSchemaContentType ContentType {
230 get { return SchemaContentType; }
233 /// <include file='doc\XmlSchemaComplexType.uex' path='docs/doc[@for="XmlSchemaComplexType.ContentTypeParticle"]/*' />
235 /// <para>[To be supplied.]</para>
238 public XmlSchemaParticle ContentTypeParticle {
239 get { return contentTypeParticle; }
242 /// <include file='doc\XmlSchemaComplexType.uex' path='docs/doc[@for="XmlSchemaComplexType.BlockResolved"]/*' />
244 /// <para>[To be supplied.]</para>
247 public XmlSchemaDerivationMethod BlockResolved {
248 get { return blockResolved; }
251 /// <include file='doc\XmlSchemaComplexType.uex' path='docs/doc[@for="XmlSchemaComplexType.AttributeUses"]/*' />
253 /// <para>[To be supplied.]</para>
256 public XmlSchemaObjectTable AttributeUses {
258 if (attributeUses == null) {
259 attributeUses = new XmlSchemaObjectTable();
261 return attributeUses;
265 /// <include file='doc\XmlSchemaComplexType.uex' path='docs/doc[@for="XmlSchemaComplexType.AttributeWildcard"]/*' />
267 /// <para>[To be supplied.]</para>
270 public XmlSchemaAnyAttribute AttributeWildcard {
271 get { return attributeWildcard; }
274 /// <include file='doc\XmlSchemaComplexType.uex' path='docs/doc[@for="XmlSchemaComplexType.LocalElements"]/*' />
276 /// <para>[To be supplied.]</para>
279 internal XmlSchemaObjectTable LocalElements {
281 if (localElements == null) {
282 localElements = new XmlSchemaObjectTable();
284 return localElements;
288 internal void SetContentTypeParticle(XmlSchemaParticle value) {
289 contentTypeParticle = value;
292 internal void SetBlockResolved(XmlSchemaDerivationMethod value) {
293 blockResolved = value;
296 internal void SetAttributeWildcard(XmlSchemaAnyAttribute value) {
297 attributeWildcard = value;
300 internal bool HasWildCard {
302 return (pvFlags & wildCardMask) != 0;
306 pvFlags = (byte)(pvFlags | wildCardMask);
309 pvFlags = (byte)(pvFlags & ~wildCardMask);
314 internal override XmlQualifiedName DerivedFrom {
316 if (contentModel == null) {
317 // type derived from anyType
318 return XmlQualifiedName.Empty;
320 if (contentModel.Content is XmlSchemaComplexContentRestriction)
321 return ((XmlSchemaComplexContentRestriction)contentModel.Content).BaseTypeName;
322 else if (contentModel.Content is XmlSchemaComplexContentExtension)
323 return ((XmlSchemaComplexContentExtension)contentModel.Content).BaseTypeName;
324 else if (contentModel.Content is XmlSchemaSimpleContentRestriction)
325 return ((XmlSchemaSimpleContentRestriction)contentModel.Content).BaseTypeName;
326 else if (contentModel.Content is XmlSchemaSimpleContentExtension)
327 return ((XmlSchemaSimpleContentExtension)contentModel.Content).BaseTypeName;
329 return XmlQualifiedName.Empty;
333 internal void SetAttributes(XmlSchemaObjectCollection newAttributes) {
334 attributes = newAttributes;
337 internal bool ContainsIdAttribute(bool findAll) {
339 foreach(XmlSchemaAttribute attribute in this.AttributeUses.Values) {
340 if (attribute.Use != XmlSchemaUse.Prohibited) {
341 XmlSchemaDatatype datatype = attribute.Datatype;
342 if (datatype != null && datatype.TypeCode == XmlTypeCode.Id) {
344 if (idCount > 1) { //two or more attributes is error
350 return findAll ? (idCount > 1) : (idCount > 0);
353 internal override XmlSchemaObject Clone() {
354 System.Diagnostics.Debug.Assert(false, "Should never call Clone() on XmlSchemaComplexType. Call Clone(XmlSchema) instead.");
358 internal XmlSchemaObject Clone(XmlSchema parentSchema) {
359 XmlSchemaComplexType complexType = (XmlSchemaComplexType)MemberwiseClone();
361 //Deep clone the QNames as these will be updated on chameleon includes
362 if (complexType.ContentModel != null) { //simpleContent or complexContent
364 XmlSchemaSimpleContent simpleContent = complexType.ContentModel as XmlSchemaSimpleContent;
365 if (simpleContent != null) {
366 XmlSchemaSimpleContent newSimpleContent = (XmlSchemaSimpleContent)simpleContent.Clone();
368 XmlSchemaSimpleContentExtension simpleExt = simpleContent.Content as XmlSchemaSimpleContentExtension;
369 if (simpleExt != null) {
370 XmlSchemaSimpleContentExtension newSimpleExt = (XmlSchemaSimpleContentExtension)simpleExt.Clone();
371 newSimpleExt.BaseTypeName = simpleExt.BaseTypeName.Clone();
372 newSimpleExt.SetAttributes(CloneAttributes(simpleExt.Attributes));
373 newSimpleContent.Content = newSimpleExt;
375 else { //simpleContent.Content is XmlSchemaSimpleContentRestriction
376 XmlSchemaSimpleContentRestriction simpleRest = (XmlSchemaSimpleContentRestriction)simpleContent.Content;
377 XmlSchemaSimpleContentRestriction newSimpleRest = (XmlSchemaSimpleContentRestriction)simpleRest.Clone();
378 newSimpleRest.BaseTypeName = simpleRest.BaseTypeName.Clone();
379 newSimpleRest.SetAttributes(CloneAttributes(simpleRest.Attributes));
380 newSimpleContent.Content = newSimpleRest;
383 complexType.ContentModel = newSimpleContent;
385 else { // complexType.ContentModel is XmlSchemaComplexContent
386 XmlSchemaComplexContent complexContent = (XmlSchemaComplexContent)complexType.ContentModel;
387 XmlSchemaComplexContent newComplexContent = (XmlSchemaComplexContent)complexContent.Clone();
389 XmlSchemaComplexContentExtension complexExt = complexContent.Content as XmlSchemaComplexContentExtension;
390 if (complexExt != null) {
391 XmlSchemaComplexContentExtension newComplexExt = (XmlSchemaComplexContentExtension)complexExt.Clone();
392 newComplexExt.BaseTypeName = complexExt.BaseTypeName.Clone();
393 newComplexExt.SetAttributes(CloneAttributes(complexExt.Attributes));
394 if (HasParticleRef(complexExt.Particle, parentSchema)) {
395 newComplexExt.Particle = CloneParticle(complexExt.Particle, parentSchema);
397 newComplexContent.Content = newComplexExt;
399 else { // complexContent.Content is XmlSchemaComplexContentRestriction
400 XmlSchemaComplexContentRestriction complexRest = complexContent.Content as XmlSchemaComplexContentRestriction;
401 XmlSchemaComplexContentRestriction newComplexRest = (XmlSchemaComplexContentRestriction)complexRest.Clone();
402 newComplexRest.BaseTypeName = complexRest.BaseTypeName.Clone();
403 newComplexRest.SetAttributes(CloneAttributes(complexRest.Attributes));
404 if (HasParticleRef(newComplexRest.Particle, parentSchema)) {
405 newComplexRest.Particle = CloneParticle(newComplexRest.Particle, parentSchema);
407 newComplexContent.Content = newComplexRest;
409 complexType.ContentModel = newComplexContent;
412 else { //equals XmlSchemaComplexContent with baseType is anyType
413 if (HasParticleRef(complexType.Particle, parentSchema)) {
414 complexType.Particle = CloneParticle(complexType.Particle, parentSchema);
416 complexType.SetAttributes(CloneAttributes(complexType.Attributes));
418 complexType.ClearCompiledState();
422 private void ClearCompiledState() {
423 //Re-set post-compiled state for cloned object
424 this.attributeUses = null;
425 this.localElements = null;
426 this.attributeWildcard = null;
427 this.contentTypeParticle = XmlSchemaParticle.Empty;
428 this.blockResolved = XmlSchemaDerivationMethod.None;
431 internal static XmlSchemaObjectCollection CloneAttributes(XmlSchemaObjectCollection attributes) {
432 if (HasAttributeQNameRef(attributes)) {
433 XmlSchemaObjectCollection newAttributes = attributes.Clone();
434 XmlSchemaAttributeGroupRef attributeGroupRef;
435 XmlSchemaAttributeGroupRef newAttGroupRef;
437 XmlSchemaAttribute att;
439 for (int i = 0; i < attributes.Count; i++) {
441 attributeGroupRef = xso as XmlSchemaAttributeGroupRef;
442 if (attributeGroupRef != null) {
443 newAttGroupRef = (XmlSchemaAttributeGroupRef)attributeGroupRef.Clone();
444 newAttGroupRef.RefName = attributeGroupRef.RefName.Clone();
445 newAttributes[i] = newAttGroupRef;
447 else { //Its XmlSchemaAttribute
448 att = xso as XmlSchemaAttribute;
449 if (!att.RefName.IsEmpty || !att.SchemaTypeName.IsEmpty) {
450 newAttributes[i] = att.Clone();
454 return newAttributes;
459 private static XmlSchemaObjectCollection CloneGroupBaseParticles(XmlSchemaObjectCollection groupBaseParticles, XmlSchema parentSchema) {
460 XmlSchemaObjectCollection newParticles = groupBaseParticles.Clone();
462 for (int i = 0; i < groupBaseParticles.Count; i++) {
463 XmlSchemaParticle p = (XmlSchemaParticle)groupBaseParticles[i];
464 newParticles[i] = CloneParticle(p, parentSchema);
469 internal static XmlSchemaParticle CloneParticle(XmlSchemaParticle particle, XmlSchema parentSchema) {
470 XmlSchemaGroupBase groupBase = particle as XmlSchemaGroupBase;
471 if (groupBase != null) { //Choice or sequence
472 XmlSchemaGroupBase newGroupBase = groupBase;
474 XmlSchemaObjectCollection newGroupbaseParticles = CloneGroupBaseParticles(groupBase.Items, parentSchema);
475 newGroupBase = (XmlSchemaGroupBase)groupBase.Clone();
476 newGroupBase.SetItems(newGroupbaseParticles);
479 else if (particle is XmlSchemaGroupRef) { // group ref
480 XmlSchemaGroupRef newGroupRef = (XmlSchemaGroupRef)particle.Clone();
481 newGroupRef.RefName = newGroupRef.RefName.Clone();
485 XmlSchemaElement oldElem = particle as XmlSchemaElement;
486 // If the particle is an element and one of the following is true:
487 // - it references another element by name
488 // - it references its type by name
489 // - it's form (effective) is qualified (meaning it will inherint namespace from chameleon includes if that happens)
490 // then the element itself needs to be cloned.
491 if (oldElem != null && (!oldElem.RefName.IsEmpty || !oldElem.SchemaTypeName.IsEmpty ||
492 GetResolvedElementForm(parentSchema, oldElem) == XmlSchemaForm.Qualified)) {
493 XmlSchemaElement newElem = (XmlSchemaElement)oldElem.Clone(parentSchema);
500 // This method returns the effective value of the "element form" for the specified element in the specified
501 // parentSchema. Element form is either qualified, unqualified or none. If it's qualified it means that
502 // if the element doesn't declare its own namespace the targetNamespace of the schema is used instead.
503 // The element form can be either specified on the element itself via the "form" attribute or
504 // if that one is not present its inheritted from the value of the elementFormDefault attribute on the owning
506 private static XmlSchemaForm GetResolvedElementForm(XmlSchema parentSchema, XmlSchemaElement element) {
507 if (element.Form == XmlSchemaForm.None && parentSchema != null) {
508 return parentSchema.ElementFormDefault;
515 internal static bool HasParticleRef(XmlSchemaParticle particle, XmlSchema parentSchema) {
516 XmlSchemaGroupBase groupBase = particle as XmlSchemaGroupBase;
517 if (groupBase != null) {
518 bool foundRef = false;
520 while (i < groupBase.Items.Count && !foundRef) {
521 XmlSchemaParticle p = (XmlSchemaParticle)groupBase.Items[i++];
522 if (p is XmlSchemaGroupRef) {
526 XmlSchemaElement elem = p as XmlSchemaElement;
527 // This is the same condition as in the CloneParticle method
528 // that's on purpose. This method is used to determine if we need to clone the whole particle.
529 // If we do, then the CloneParticle is called and it will try to clone only
530 // those elements which need cloning - and those are the ones matching this condition.
531 if (elem != null && (!elem.RefName.IsEmpty || !elem.SchemaTypeName.IsEmpty ||
532 GetResolvedElementForm(parentSchema, elem) == XmlSchemaForm.Qualified)) {
536 foundRef = HasParticleRef(p, parentSchema);
542 else if (particle is XmlSchemaGroupRef) {
548 internal static bool HasAttributeQNameRef(XmlSchemaObjectCollection attributes) {
549 for (int i = 0; i < attributes.Count; ++i) {
550 if (attributes[i] is XmlSchemaAttributeGroupRef) {
554 XmlSchemaAttribute attribute = attributes[i] as XmlSchemaAttribute;
555 if (!attribute.RefName.IsEmpty || !attribute.SchemaTypeName.IsEmpty) {