The Labs \ Source Viewer \ SSCLI \ System.Xml.XPath.DataBinding \ XmlSchemaAttributeComparer

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

Developer Fusion