The Labs \ Source Viewer \ SSCLI \ System.Xml.Serialization \ SchemaGraph

  1. //------------------------------------------------------------------------------
  2. // <copyright file="ImportContext.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. // <owner current="true" primary="true">ElenaK</owner>
  15. //------------------------------------------------------------------------------
  16. namespace System.Xml.Serialization
  17. {
  18.     using System;
  19.     using System.IO;
  20.     using System.Xml;
  21.     using System.Xml.Schema;
  22.     using System.Xml.Serialization;
  23.     using System.Collections;
  24.     using System.Collections.Specialized;
  25.    
  26.     public class ImportContext
  27.     {
  28.         bool shareTypes;
  29.         SchemaObjectCache cache;
  30.         // cached schema top-level items
  31.         Hashtable mappings;
  32.         // XmlSchema -> SerializableMapping, XmlSchemaSimpleType -> EnumMapping, XmlSchemaComplexType -> StructMapping
  33.         Hashtable elements;
  34.         // XmlSchemaElement -> ElementAccessor
  35.         CodeIdentifiers typeIdentifiers;
  36.        
  37.         /// <include file='doc\ImportContext.uex' path='docs/doc[@for="ImportContext.ImportContext"]/*' />
  38.         /// <devdoc>
  39.         /// <para>[To be supplied.]</para>
  40.         /// </devdoc>
  41.         public ImportContext(CodeIdentifiers identifiers, bool shareTypes)
  42.         {
  43.             this.typeIdentifiers = identifiers;
  44.             this.shareTypes = shareTypes;
  45.         }
  46.         internal ImportContext() : this(null, false)
  47.         {
  48.         }
  49.        
  50.         internal SchemaObjectCache Cache {
  51.             get {
  52.                 if (cache == null)
  53.                     cache = new SchemaObjectCache();
  54.                 return cache;
  55.             }
  56.         }
  57.        
  58.         internal Hashtable Elements {
  59.             get {
  60.                 if (elements == null)
  61.                     elements = new Hashtable();
  62.                 return elements;
  63.             }
  64.         }
  65.        
  66.         internal Hashtable Mappings {
  67.             get {
  68.                 if (mappings == null)
  69.                     mappings = new Hashtable();
  70.                 return mappings;
  71.             }
  72.         }
  73.        
  74.         /// <include file='doc\ImportContext.uex' path='docs/doc[@for="ImportContext.TypeIdentifiers"]/*' />
  75.         /// <devdoc>
  76.         /// <para>[To be supplied.]</para>
  77.         /// </devdoc>
  78.         public CodeIdentifiers TypeIdentifiers {
  79.             get {
  80.                 if (typeIdentifiers == null)
  81.                     typeIdentifiers = new CodeIdentifiers();
  82.                 return typeIdentifiers;
  83.             }
  84.         }
  85.        
  86.         /// <include file='doc\ImportContext.uex' path='docs/doc[@for="ImportContext.ShareTypes"]/*' />
  87.         /// <devdoc>
  88.         /// <para>[To be supplied.]</para>
  89.         /// </devdoc>
  90.         public bool ShareTypes {
  91.             get { return shareTypes; }
  92.         }
  93.        
  94.         /// <include file='doc\ImportContext.uex' path='docs/doc[@for="ImportContext.Warnings"]/*' />
  95.         /// <devdoc>
  96.         /// <para>[To be supplied.]</para>
  97.         /// </devdoc>
  98.         public StringCollection Warnings {
  99.             get { return Cache.Warnings; }
  100.         }
  101.     }
  102.    
  103.     internal class SchemaObjectCache
  104.     {
  105.         Hashtable graph;
  106.         Hashtable hash;
  107.         Hashtable objectCache;
  108.         StringCollection warnings;
  109.         internal Hashtable looks = new Hashtable();
  110.         Hashtable Graph {
  111.             get {
  112.                 if (graph == null)
  113.                     graph = new Hashtable();
  114.                 return graph;
  115.             }
  116.         }
  117.        
  118.         Hashtable Hash {
  119.             get {
  120.                 if (hash == null)
  121.                     hash = new Hashtable();
  122.                 return hash;
  123.             }
  124.         }
  125.        
  126.         Hashtable ObjectCache {
  127.             get {
  128.                 if (objectCache == null)
  129.                     objectCache = new Hashtable();
  130.                 return objectCache;
  131.             }
  132.         }
  133.        
  134.         internal StringCollection Warnings {
  135.             get {
  136.                 if (warnings == null)
  137.                     warnings = new StringCollection();
  138.                 return warnings;
  139.             }
  140.         }
  141.        
  142.         internal XmlSchemaObject AddItem(XmlSchemaObject item, XmlQualifiedName qname, XmlSchemas schemas)
  143.         {
  144.             if (item == null)
  145.                 return null;
  146.             if (qname == null || qname.IsEmpty)
  147.                 return null;
  148.            
  149.             string key = item.GetType().Name + ":" + qname.ToString();
  150.             ArrayList list = (ArrayList)ObjectCache[key];
  151.             if (list == null) {
  152.                 list = new ArrayList();
  153.                 ObjectCache[key] = list;
  154.             }
  155.            
  156.             for (int i = 0; i < list.Count; i++) {
  157.                 XmlSchemaObject cachedItem = (XmlSchemaObject)list[i];
  158.                 if (cachedItem == item)
  159.                     return cachedItem;
  160.                
  161.                 if (Match(cachedItem, item, true)) {
  162.                     return cachedItem;
  163.                 }
  164.                 else {
  165.                     Warnings.Add(Res.GetString(Res.XmlMismatchSchemaObjects, item.GetType().Name, qname.Name, qname.Namespace));
  166.                     Warnings.Add("DEBUG:Cached item key:\r\n" + (string)looks[cachedItem] + "\r\nnew item key:\r\n" + (string)looks[item]);
  167.                 }
  168.             }
  169.             // no match found we need to insert the new type in the cache
  170.             list.Add(item);
  171.             return item;
  172.         }
  173.        
  174.         internal bool Match(XmlSchemaObject o1, XmlSchemaObject o2, bool shareTypes)
  175.         {
  176.             if (o1 == o2)
  177.                 return true;
  178.             if (o1.GetType() != o2.GetType())
  179.                 return false;
  180.             if (Hash[o1] == null)
  181.                 Hash[o1] = GetHash(o1);
  182.             int hash1 = (int)Hash[o1];
  183.             int hash2 = GetHash(o2);
  184.             if (hash1 != hash2)
  185.                 return false;
  186.            
  187.             if (shareTypes)
  188.                 return CompositeHash(o1, hash1) == CompositeHash(o2, hash2);
  189.             return true;
  190.         }
  191.        
  192.         private ArrayList GetDependencies(XmlSchemaObject o, ArrayList deps, Hashtable refs)
  193.         {
  194.             if (refs[o] == null) {
  195.                 refs[o] = o;
  196.                 deps.Add(o);
  197.                 ArrayList list = Graph[o] as ArrayList;
  198.                 if (list != null) {
  199.                     for (int i = 0; i < list.Count; i++) {
  200.                         GetDependencies((XmlSchemaObject)list[i], deps, refs);
  201.                     }
  202.                 }
  203.             }
  204.             return deps;
  205.         }
  206.        
  207.         private int CompositeHash(XmlSchemaObject o, int hash)
  208.         {
  209.             ArrayList list = GetDependencies(o, new ArrayList(), new Hashtable());
  210.             double tmp = 0;
  211.             for (int i = 0; i < list.Count; i++) {
  212.                 object cachedHash = Hash[list[i]];
  213.                 if (cachedHash is int) {
  214.                     tmp += (int)cachedHash / list.Count;
  215.                 }
  216.             }
  217.             return (int)tmp;
  218.         }
  219.        
  220.         internal void GenerateSchemaGraph(XmlSchemas schemas)
  221.         {
  222.             SchemaGraph graph = new SchemaGraph(Graph, schemas);
  223.             ArrayList items = graph.GetItems();
  224.            
  225.             for (int i = 0; i < items.Count; i++) {
  226.                 GetHash((XmlSchemaObject)items[i]);
  227.             }
  228.         }
  229.        
  230.         private int GetHash(XmlSchemaObject o)
  231.         {
  232.             object hash = Hash[o];
  233.             if (hash != null) {
  234.                 if (hash is XmlSchemaObject) {
  235.                 }
  236.                 else {
  237.                     return (int)hash;
  238.                 }
  239.             }
  240.             // new object, generate the hash
  241.             string hashString = ToString(o, new SchemaObjectWriter());
  242.             looks[o] = hashString;
  243.             int code = hashString.GetHashCode();
  244.             Hash[o] = code;
  245.             return code;
  246.         }
  247.        
  248.         string ToString(XmlSchemaObject o, SchemaObjectWriter writer)
  249.         {
  250.             return writer.WriteXmlSchemaObject(o);
  251.         }
  252.     }
  253.    
  254.     internal class SchemaGraph
  255.     {
  256.         ArrayList empty = new ArrayList();
  257.         XmlSchemas schemas;
  258.         Hashtable scope;
  259.         int items;
  260.        
  261.         internal SchemaGraph(Hashtable scope, XmlSchemas schemas)
  262.         {
  263.             this.scope = scope;
  264.             schemas.Compile(null, false);
  265.             this.schemas = schemas;
  266.             items = 0;
  267.             foreach (XmlSchema s in schemas) {
  268.                 items += s.Items.Count;
  269.                 foreach (XmlSchemaObject item in s.Items) {
  270.                     Depends(item);
  271.                 }
  272.             }
  273.         }
  274.        
  275.         internal ArrayList GetItems()
  276.         {
  277.             return new ArrayList(scope.Keys);
  278.         }
  279.        
  280.         internal void AddRef(ArrayList list, XmlSchemaObject o)
  281.         {
  282.             if (o == null)
  283.                 return;
  284.             if (schemas.IsReference(o))
  285.                 return;
  286.             if (o.Parent is XmlSchema) {
  287.                 string ns = ((XmlSchema)o.Parent).TargetNamespace;
  288.                 if (ns == XmlSchema.Namespace)
  289.                     return;
  290.                 if (list.Contains(o))
  291.                     return;
  292.                 list.Add(o);
  293.             }
  294.         }
  295.        
  296.         internal ArrayList Depends(XmlSchemaObject item)
  297.         {
  298.            
  299.             if (item.Parent is XmlSchema) {
  300.                 if (scope[item] != null)
  301.                     return (ArrayList)scope[item];
  302.                
  303.                 ArrayList refs = new ArrayList();
  304.                 Depends(item, refs);
  305.                 scope.Add(item, refs);
  306.                 return refs;
  307.             }
  308.             return empty;
  309.         }
  310.        
  311.         internal void Depends(XmlSchemaObject item, ArrayList refs)
  312.         {
  313.             if (item == null || scope[item] != null)
  314.                 return;
  315.            
  316.             Type t = item.GetType();
  317.             if (typeof(XmlSchemaType).IsAssignableFrom(t)) {
  318.                 XmlQualifiedName baseName = XmlQualifiedName.Empty;
  319.                 XmlSchemaType baseType = null;
  320.                 XmlSchemaParticle particle = null;
  321.                 XmlSchemaObjectCollection attributes = null;
  322.                
  323.                 if (item is XmlSchemaComplexType) {
  324.                     XmlSchemaComplexType ct = (XmlSchemaComplexType)item;
  325.                     if (ct.ContentModel != null) {
  326.                         XmlSchemaContent content = ct.ContentModel.Content;
  327.                         if (content is XmlSchemaComplexContentRestriction) {
  328.                             baseName = ((XmlSchemaComplexContentRestriction)content).BaseTypeName;
  329.                             attributes = ((XmlSchemaComplexContentRestriction)content).Attributes;
  330.                         }
  331.                         else if (content is XmlSchemaSimpleContentRestriction) {
  332.                             XmlSchemaSimpleContentRestriction restriction = (XmlSchemaSimpleContentRestriction)content;
  333.                             if (restriction.BaseType != null)
  334.                                 baseType = restriction.BaseType;
  335.                             else
  336.                                 baseName = restriction.BaseTypeName;
  337.                             attributes = restriction.Attributes;
  338.                         }
  339.                         else if (content is XmlSchemaComplexContentExtension) {
  340.                             XmlSchemaComplexContentExtension extension = (XmlSchemaComplexContentExtension)content;
  341.                             attributes = extension.Attributes;
  342.                             particle = extension.Particle;
  343.                             baseName = extension.BaseTypeName;
  344.                         }
  345.                         else if (content is XmlSchemaSimpleContentExtension) {
  346.                             XmlSchemaSimpleContentExtension extension = (XmlSchemaSimpleContentExtension)content;
  347.                             attributes = extension.Attributes;
  348.                             baseName = extension.BaseTypeName;
  349.                         }
  350.                     }
  351.                     else {
  352.                         attributes = ct.Attributes;
  353.                         particle = ct.Particle;
  354.                     }
  355.                     if (particle is XmlSchemaGroupRef) {
  356.                         XmlSchemaGroupRef refGroup = (XmlSchemaGroupRef)particle;
  357.                         particle = ((XmlSchemaGroup)schemas.Find(refGroup.RefName, typeof(XmlSchemaGroup), false)).Particle;
  358.                     }
  359.                     else if (particle is XmlSchemaGroupBase) {
  360.                         particle = (XmlSchemaGroupBase)particle;
  361.                     }
  362.                 }
  363.                 else if (item is XmlSchemaSimpleType) {
  364.                     XmlSchemaSimpleType simpleType = (XmlSchemaSimpleType)item;
  365.                     XmlSchemaSimpleTypeContent content = simpleType.Content;
  366.                     if (content is XmlSchemaSimpleTypeRestriction) {
  367.                         baseType = ((XmlSchemaSimpleTypeRestriction)content).BaseType;
  368.                         baseName = ((XmlSchemaSimpleTypeRestriction)content).BaseTypeName;
  369.                     }
  370.                     else if (content is XmlSchemaSimpleTypeList) {
  371.                         XmlSchemaSimpleTypeList list = (XmlSchemaSimpleTypeList)content;
  372.                         if (list.ItemTypeName != null && !list.ItemTypeName.IsEmpty)
  373.                             baseName = list.ItemTypeName;
  374.                         if (list.ItemType != null) {
  375.                             baseType = list.ItemType;
  376.                         }
  377.                     }
  378.                     else if (content is XmlSchemaSimpleTypeRestriction) {
  379.                         baseName = ((XmlSchemaSimpleTypeRestriction)content).BaseTypeName;
  380.                     }
  381.                     else if (t == typeof(XmlSchemaSimpleTypeUnion)) {
  382.                         XmlQualifiedName[] memberTypes = ((XmlSchemaSimpleTypeUnion)item).MemberTypes;
  383.                        
  384.                         if (memberTypes != null) {
  385.                             for (int i = 0; i < memberTypes.Length; i++) {
  386.                                 XmlSchemaType type = (XmlSchemaType)schemas.Find(memberTypes[i], typeof(XmlSchemaType), false);
  387.                                 AddRef(refs, type);
  388.                             }
  389.                         }
  390.                     }
  391.                 }
  392.                 if (baseType == null && !baseName.IsEmpty && baseName.Namespace != XmlSchema.Namespace)
  393.                     baseType = (XmlSchemaType)schemas.Find(baseName, typeof(XmlSchemaType), false);
  394.                
  395.                 if (baseType != null) {
  396.                     AddRef(refs, baseType);
  397.                 }
  398.                 if (particle != null) {
  399.                     Depends(particle, refs);
  400.                 }
  401.                 if (attributes != null) {
  402.                     for (int i = 0; i < attributes.Count; i++) {
  403.                         Depends(attributes[i], refs);
  404.                     }
  405.                 }
  406.             }
  407.             else if (t == typeof(XmlSchemaElement)) {
  408.                 XmlSchemaElement el = (XmlSchemaElement)item;
  409.                 if (!el.SubstitutionGroup.IsEmpty) {
  410.                     if (el.SubstitutionGroup.Namespace != XmlSchema.Namespace) {
  411.                         XmlSchemaElement head = (XmlSchemaElement)schemas.Find(el.SubstitutionGroup, typeof(XmlSchemaElement), false);
  412.                         AddRef(refs, head);
  413.                     }
  414.                 }
  415.                 if (!el.RefName.IsEmpty) {
  416.                     el = (XmlSchemaElement)schemas.Find(el.RefName, typeof(XmlSchemaElement), false);
  417.                     AddRef(refs, el);
  418.                 }
  419.                 else if (!el.SchemaTypeName.IsEmpty) {
  420.                     XmlSchemaType type = (XmlSchemaType)schemas.Find(el.SchemaTypeName, typeof(XmlSchemaType), false);
  421.                     AddRef(refs, type);
  422.                 }
  423.                 else {
  424.                     Depends(el.SchemaType, refs);
  425.                 }
  426.             }
  427.             else if (t == typeof(XmlSchemaGroup)) {
  428.                 Depends(((XmlSchemaGroup)item).Particle);
  429.             }
  430.             else if (t == typeof(XmlSchemaGroupRef)) {
  431.                 XmlSchemaGroup group = (XmlSchemaGroup)schemas.Find(((XmlSchemaGroupRef)item).RefName, typeof(XmlSchemaGroup), false);
  432.                 AddRef(refs, group);
  433.             }
  434.             else if (typeof(XmlSchemaGroupBase).IsAssignableFrom(t)) {
  435.                 foreach (XmlSchemaObject o in ((XmlSchemaGroupBase)item).Items) {
  436.                     Depends(o, refs);
  437.                 }
  438.             }
  439.             else if (t == typeof(XmlSchemaAttributeGroupRef)) {
  440.                 XmlSchemaAttributeGroup group = (XmlSchemaAttributeGroup)schemas.Find(((XmlSchemaAttributeGroupRef)item).RefName, typeof(XmlSchemaAttributeGroup), false);
  441.                 AddRef(refs, group);
  442.             }
  443.             else if (t == typeof(XmlSchemaAttributeGroup)) {
  444.                 foreach (XmlSchemaObject o in ((XmlSchemaAttributeGroup)item).Attributes) {
  445.                     Depends(o, refs);
  446.                 }
  447.             }
  448.             else if (t == typeof(XmlSchemaAttribute)) {
  449.                 XmlSchemaAttribute at = (XmlSchemaAttribute)item;
  450.                 if (!at.RefName.IsEmpty) {
  451.                     at = (XmlSchemaAttribute)schemas.Find(at.RefName, typeof(XmlSchemaAttribute), false);
  452.                     AddRef(refs, at);
  453.                 }
  454.                 else if (!at.SchemaTypeName.IsEmpty) {
  455.                     XmlSchemaType type = (XmlSchemaType)schemas.Find(at.SchemaTypeName, typeof(XmlSchemaType), false);
  456.                     AddRef(refs, type);
  457.                 }
  458.                 else {
  459.                     Depends(at.SchemaType, refs);
  460.                 }
  461.             }
  462.             if (typeof(XmlSchemaAnnotated).IsAssignableFrom(t)) {
  463.                 XmlAttribute[] attrs = (XmlAttribute[])((XmlSchemaAnnotated)item).UnhandledAttributes;
  464.                
  465.                 if (attrs != null) {
  466.                     for (int i = 0; i < attrs.Length; i++) {
  467.                         XmlAttribute attribute = attrs[i];
  468.                         if (attribute.LocalName == Wsdl.ArrayType && attribute.NamespaceURI == Wsdl.Namespace) {
  469.                             string dims;
  470.                             XmlQualifiedName qname = TypeScope.ParseWsdlArrayType(attribute.Value, out dims, item);
  471.                             XmlSchemaType type = (XmlSchemaType)schemas.Find(qname, typeof(XmlSchemaType), false);
  472.                             AddRef(refs, type);
  473.                         }
  474.                     }
  475.                 }
  476.             }
  477.         }
  478.     }
  479. }

Developer Fusion