private void TraverseParticle(XmlSchemaParticle particle, XmlSchemaComplexType baseType, ClrContentTypeInfo typeInfo, XmlSchemaDerivationMethod derivationMethod) { if (particleStack == null) { particleStack = new Stack<ParticleData>(); } else { particleStack.Clear(); } if (propertyNameTypeTable == null) { propertyNameTypeTable = new Dictionary<string, ClrPropertyInfo>(); } else { propertyNameTypeTable.Clear(); } XmlSchemaParticle baseParticle = baseType.ContentTypeParticle; ParticleData particleData; GroupingInfo parentGroupInfo = null; StringBuilder regEx = new StringBuilder(); XmlSchemaGroupBase currentGroupBase = null; GroupingInfo currentGroupingInfo = null; int currentIndex = 0; while (true) { // dont interrogate a particle if we are past the end of the list if (currentGroupBase == null || currentIndex <= currentGroupBase.Items.Count) { ParticleType particleType = particle.GetParticleType(); switch (particleType) { case ParticleType.Element: { XmlSchemaElement elem = particle as XmlSchemaElement; ClrPropertyInfo propertyInfo = null; bool fromBaseType = false; if (derivationMethod == XmlSchemaDerivationMethod.Extension && typeInfo.IsDerived) { if (baseParticle.ContainsElement(elem)) { fromBaseType = true; } else if (!typeInfo.InlineBaseType && baseType.ContainsName(elem.QualifiedName)) { typeInfo.InlineBaseType = true; } } propertyInfo = BuildProperty(elem, fromBaseType); regEx.Append(propertyInfo.PropertyName); AppendOccurenceToRegex(propertyInfo, regEx); //Add to parent if (currentGroupingInfo == null) { //Not adding property to propertyNameTypeTable as this case will occur only for pointless groups, so they have just one property BuildAnnotationInformation(propertyInfo, elem, false, false); typeInfo.AddMember(propertyInfo); } else { BuildAnnotationInformation(propertyInfo, elem, currentGroupingInfo.ContentModelType == ContentModelType.Choice, currentGroupingInfo.IsNested); currentGroupingInfo.AddChild(propertyInfo); SetPropertyFlags(propertyInfo, currentGroupingInfo, elem.ElementSchemaType); } break; } case ParticleType.Any: { regEx.Append("any"); XmlSchemaAny any = particle as XmlSchemaAny; if (derivationMethod == XmlSchemaDerivationMethod.Extension && typeInfo.IsDerived) { if (baseParticle.ContainsWildCard(any)) { typeInfo.HasElementWildCard = true;//ANY property in the base type will be reused } } //Note we always create a property info object to keep the original nesting structure in the schema //so it can be used to create a correct FSM; on the other hand, typeInfo.HasElementWildCard will indicate whether //we need to create a property in the resulting object type. ClrWildCardPropertyInfo wcPropertyInfo = BuildAnyProperty(any, !typeInfo.HasElementWildCard); //Add to parent if (currentGroupingInfo == null) { typeInfo.AddMember(wcPropertyInfo); } else { currentGroupingInfo.AddChild(wcPropertyInfo); } if (!typeInfo.HasElementWildCard) typeInfo.HasElementWildCard = true; break; } case ParticleType.Sequence: case ParticleType.Choice: case ParticleType.All: regEx.Append("("); if (currentGroupBase != null) { //already there is a group that we are processing, push it on stack to process sub-group particleStack.Push(new ParticleData(currentGroupBase, currentGroupingInfo, currentIndex)); currentIndex = 0; //Re-start index for new group base } parentGroupInfo = currentGroupingInfo; //Assign parent before creating child groupInfo currentGroupBase = particle as XmlSchemaGroupBase; Debug.Assert(currentGroupBase != null); currentGroupingInfo = new GroupingInfo((ContentModelType)((int)particleType), GetOccurence(currentGroupBase)); //Add to parent if (parentGroupInfo == null) { typeInfo.AddMember(currentGroupingInfo); parentGroupInfo = currentGroupingInfo; //Assign first time } else { parentGroupInfo.AddChild(currentGroupingInfo); parentGroupInfo.HasChildGroups = true; currentGroupingInfo.IsNested = true; if (parentGroupInfo.IsRepeating) { currentGroupingInfo.IsRepeating = true; } if (currentGroupingInfo.IsRepeating) { parentGroupInfo.HasRepeatingGroups = true; } } break; } } //Drill down into items if (currentGroupBase != null && currentIndex < currentGroupBase.Items.Count) { // if this isnt the first, then we need a seperator if (currentIndex > 0) { regEx.Append(currentGroupingInfo.ContentModelType == ContentModelType.Choice ? " | " : ", "); } particle = (XmlSchemaParticle)currentGroupBase.Items[currentIndex++]; } else { if (currentGroupBase != null) { regEx.Append(")"); AppendOccurenceToRegex(currentGroupingInfo, regEx); } if (particleStack.Count > 0) { bool childGroupHasRecurringElements = currentGroupingInfo.HasRecurrentElements; bool childGroupHasRepeatingGroups = currentGroupingInfo.HasRepeatingGroups; particleData = particleStack.Pop(); currentGroupBase = particleData.currentGroupBase; currentGroupingInfo = particleData.currentGroupingInfo; currentGroupingInfo.HasRecurrentElements = childGroupHasRecurringElements; currentGroupingInfo.HasRepeatingGroups = childGroupHasRepeatingGroups; currentIndex = particleData.currentIndex; if (currentIndex < currentGroupBase.Items.Count) { particle = (XmlSchemaParticle)currentGroupBase.Items[currentIndex++]; regEx.Append(currentGroupingInfo.ContentModelType == ContentModelType.Choice ? "|" : ", "); } else { // we were already at the end of the parent group, so just continue currentIndex++; //we are off the end of this list } } else { //No more particles to process break; } } } if (regEx.Length != 0) { typeInfo.ContentModelRegEx = regEx.ToString(); } }