1 //------------------------------------------------------------------------------ 2 // <copyright file="ShapeGenerator.cs" company="Microsoft"> 3 // Copyright (c) Microsoft Corporation. All rights reserved. 4 // </copyright> 5 // <owner current="true" primary="true">derekdb</owner> 6 //------------------------------------------------------------------------------ 7 #if ENABLEDATABINDING 8 using System; 9 using System.Xml; 10 using System.Xml.Schema; 11 using System.Xml.XPath; 12 using System.Collections; 13 using System.Diagnostics; 14 using System.ComponentModel; 15 using System.Text; 16 17 namespace System.Xml.XPath.DataBinding 18 { 19 internal sealed class ShapeGenerator 20 { 21 private Hashtable elementTypesProcessed; 22 private IXmlNamespaceResolver nsResolver; 23 ShapeGenerator(IXmlNamespaceResolver nsResolver)24 public ShapeGenerator(IXmlNamespaceResolver nsResolver) { 25 this.elementTypesProcessed = new Hashtable(); 26 this.nsResolver = nsResolver; 27 } 28 GenerateFromSchema(XmlSchemaElement xse)29 public Shape GenerateFromSchema(XmlSchemaElement xse) { 30 XmlQualifiedName xseName = xse.QualifiedName; 31 XmlSchemaType schemaType = xse.ElementSchemaType; 32 XmlSchemaComplexType complexType = schemaType as XmlSchemaComplexType; 33 if (null != complexType) { 34 XmlSchemaParticle particle = null; 35 Shape rootShape = null; 36 37 XmlSchemaContentType contentType = complexType.ElementDecl.ContentValidator.ContentType; 38 switch (contentType) { 39 case XmlSchemaContentType.Mixed: 40 case XmlSchemaContentType.TextOnly: 41 rootShape = new Shape(GenName(xseName) + "_Text", BindingType.Text); 42 rootShape.AddParticle(xse); 43 break; 44 45 case XmlSchemaContentType.Empty: 46 rootShape = new Shape(null, BindingType.Sequence); 47 break; 48 49 case XmlSchemaContentType.ElementOnly: 50 particle = complexType.ContentTypeParticle; 51 rootShape = ProcessParticle(particle, null); 52 break; 53 54 } 55 56 Debug.Assert(rootShape != null); 57 if (complexType.AttributeUses.Values.Count > 0) { 58 if (rootShape.BindingType != BindingType.Sequence) { 59 Shape s = new Shape(null, BindingType.Sequence); 60 s.AddSubShape(rootShape); 61 rootShape = s; 62 } 63 int pos = 0; 64 string[] names = rootShape.SubShapeNames(); 65 66 ICollection attributes = complexType.AttributeUses.Values; 67 XmlSchemaAttribute[] xsaArray = new XmlSchemaAttribute[attributes.Count]; 68 attributes.CopyTo(xsaArray, 0); 69 Array.Sort(xsaArray, new XmlSchemaAttributeComparer()); 70 foreach(XmlSchemaAttribute xsa in xsaArray) { 71 string name = GenAttrName(xsa.QualifiedName, names); 72 Shape attrShape = new Shape(name, BindingType.Attribute); 73 attrShape.AddParticle(xsa); 74 rootShape.AddAttrShapeAt(attrShape, pos++); 75 } 76 } 77 78 if (rootShape.BindingType != BindingType.Text) { 79 rootShape.Name = GenName(xseName); 80 rootShape.ContainerDecl = xse; 81 } 82 return rootShape; 83 } 84 else { // simple type 85 Shape s = new Shape(GenName(xseName), BindingType.Text); 86 s.AddParticle(xse); 87 return s; 88 } 89 } 90 GenerateFromSchema(XmlSchemaAttribute xsa)91 public Shape GenerateFromSchema(XmlSchemaAttribute xsa) { 92 Shape s = new Shape(GenName(xsa.QualifiedName), BindingType.Attribute); 93 s.AddParticle(xsa); 94 return s; 95 } 96 ProcessParticle(XmlSchemaParticle xsp, Shape parent)97 Shape ProcessParticle(XmlSchemaParticle xsp, Shape parent) { 98 Shape s; 99 if (xsp == XmlSchemaParticle.Empty) { 100 return null; 101 } 102 if (xsp is XmlSchemaElement) { 103 s = ProcessParticleElement((XmlSchemaElement)xsp); 104 } 105 else if (xsp is XmlSchemaSequence) { 106 s = ProcessParticleGroup((XmlSchemaSequence)xsp, BindingType.Sequence); 107 } 108 else if (xsp is XmlSchemaChoice) { 109 s = ProcessParticleGroup((XmlSchemaChoice)xsp, BindingType.Choice); 110 } 111 else if (xsp is XmlSchemaAll) { 112 s = ProcessParticleGroup((XmlSchemaAll)xsp, BindingType.All); 113 } 114 else { //XmlSchemaAny 115 return null; //Ignore Any in the content model 116 } 117 if (xsp.MaxOccurs > 1) { 118 Shape rep = new Shape(s.Name, BindingType.Repeat); 119 rep.AddSubShape(s); 120 s = rep; 121 } 122 if (parent != null) 123 parent.AddSubShape(s); 124 return s; 125 } 126 ProcessParticleElement(XmlSchemaElement xse)127 Shape ProcessParticleElement(XmlSchemaElement xse) { 128 // watch out for recursive schema 129 Shape s = (Shape)this.elementTypesProcessed[xse]; 130 if (null != s) 131 return s; 132 133 bool complex = xse.ElementSchemaType is XmlSchemaComplexType; 134 s = new Shape(GenName(xse.QualifiedName), complex ? BindingType.ElementNested : BindingType.Element); 135 s.AddParticle(xse); 136 137 if (complex) { 138 this.elementTypesProcessed.Add(xse, s); 139 s.NestedShape = GenerateFromSchema(xse); 140 this.elementTypesProcessed.Remove(xse); 141 } 142 return s; 143 } 144 ProcessParticleGroup(XmlSchemaGroupBase xsg, BindingType bt)145 Shape ProcessParticleGroup(XmlSchemaGroupBase xsg, BindingType bt) { 146 Shape s = new Shape(null, bt); 147 StringBuilder sb = new StringBuilder(); 148 foreach (XmlSchemaParticle xsp in xsg.Items) { 149 Shape sub = ProcessParticle(xsp, s); 150 if (sub != null) { //sub can be null if the child particle is xs:any 151 if (sb.Length > 0) 152 sb.Append('_'); 153 sb.Append(sub.Name); 154 } 155 } 156 // need to also test if paretn != null for this to work 157 //if (s.IsGroup && s.SubShapes.Count == 1) { 158 // Shape sub = (Shape)s.SubShapes[0]; 159 // s.Clear(); 160 // return sub; 161 //} 162 s.Name = sb.ToString(); 163 return s; 164 } 165 GenName(XmlQualifiedName xqn)166 string GenName(XmlQualifiedName xqn) { 167 string ns = xqn.Namespace; 168 string ln = xqn.Name; 169 if (ns.Length != 0) { 170 string prefix = (null==this.nsResolver) ? null : this.nsResolver.LookupPrefix(ns); 171 if (prefix != null && prefix.Length != 0) 172 return String.Concat(prefix, ":", ln); 173 } 174 return ln; 175 } 176 GenAttrName(XmlQualifiedName xqn, string[] names)177 string GenAttrName(XmlQualifiedName xqn, string[] names) { 178 string name = GenName(xqn); 179 if (null != names) { 180 for (int i=0; i<names.Length; i++) { 181 if (name == names[i]) { 182 return String.Concat("@", name); 183 } 184 } 185 } 186 return name; 187 } 188 ResetState()189 public void ResetState() { 190 this.elementTypesProcessed.Clear(); 191 } 192 193 class XmlSchemaAttributeComparer : IComparer { Compare(object a, object b)194 public virtual int Compare(object a, object b) { 195 XmlSchemaAttribute xsaA = (XmlSchemaAttribute)a; 196 XmlSchemaAttribute xsaB = (XmlSchemaAttribute)b; 197 return XmlQualifiedName.Compare(xsaA.QualifiedName, xsaB.QualifiedName); 198 } 199 } 200 } 201 } 202 #endif