ShapeGenerator.cs 7.8 KB

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