SchemaCache.cs
上传用户:hbhltzc
上传日期:2022-06-04
资源大小:1925k
文件大小:18k
源码类别:

xml/soap/webservice

开发平台:

Visual C++

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Text;
  4. using System.Xml;
  5. using System.Xml.Schema;
  6. using System.IO;
  7. using System.Globalization;
  8. using System.Xml.Serialization;
  9. namespace XmlNotepad
  10. {
  11.     /// <summary>
  12.     /// This class represents a cached schema which may or may not be loaded yet.
  13.     /// This allows delay loading of schemas.
  14.     /// </summary>
  15.     public class CacheEntry {
  16.         string targetNamespace;
  17.         Uri location;
  18.         XmlSchema schema;
  19.         bool disabled;
  20.         string fileName;
  21.         DateTime lastModified;
  22.         CacheEntry next; // entry with same targetNamespace;
  23.         public string TargetNamespace {
  24.             get { return targetNamespace; }
  25.             set { targetNamespace = value; }
  26.         }
  27.         public Uri Location {
  28.             get { return location; }
  29.             set { location = value; 
  30.                 schema = null;
  31.                 if (location.IsFile) {
  32.                     fileName = location.LocalPath;
  33.                 }
  34.             }
  35.         }
  36.         public bool HasUpToDateSchema {
  37.             get {
  38.                 if (schema == null) return false;
  39.                 if (fileName != null) {
  40.                     DateTime lastWriteTime = File.GetLastWriteTime(fileName);
  41.                     if (lastWriteTime > this.lastModified) {
  42.                         return false;
  43.                     }
  44.                 }
  45.                 return true;
  46.             }
  47.         }
  48.         public XmlSchema Schema {
  49.             get { return schema; }
  50.             set {
  51.                 if (schema != value) {
  52.                     schema = value;
  53.                     if (fileName != null) {
  54.                         this.lastModified = File.GetLastWriteTime(fileName);
  55.                     }
  56.                 }
  57.             }
  58.         }
  59.         public CacheEntry Next {
  60.             get { return next; }
  61.             set { next = value; }
  62.         }
  63.         public bool Disabled {
  64.             get { return disabled; }
  65.             set { disabled = value; }
  66.         }
  67.         public CacheEntry FindByUri(Uri uri) {
  68.             CacheEntry e = this;
  69.             while (e != null) {
  70.                 if (e.location == uri) {
  71.                     return e;
  72.                 }
  73.                 e = e.next;
  74.             }
  75.             return null;
  76.         }
  77.         // Remove the given cache entry and return the new head of the linked list.
  78.         public CacheEntry RemoveUri(Uri uri) {
  79.             CacheEntry e = this;
  80.             CacheEntry previous = null;
  81.             while (e != null) {
  82.                 if (e.location == uri) {
  83.                     if (previous == null) {
  84.                         return e.next; // return new head
  85.                     }
  86.                     previous.next = e.next; //unlink it
  87.                     return this; // head is unchanged.
  88.                 }
  89.                 previous = e;
  90.                 e = e.next;
  91.             }
  92.             return this;
  93.         }
  94.         public void Add(CacheEntry newEntry) {
  95.             CacheEntry e = this;
  96.             while (e != null) {
  97.                 if (e == newEntry) {
  98.                     return;
  99.                 }
  100.                 if (e.location == newEntry.location) {
  101.                     e.schema = newEntry.schema;
  102.                     e.lastModified = newEntry.lastModified;
  103.                     e.disabled = newEntry.disabled;
  104.                     return;
  105.                 }
  106.                 if (e.next == null) {
  107.                     e.next = newEntry;
  108.                     break;
  109.                 }
  110.                 e = e.next;
  111.             }
  112.         }
  113.     }
  114.     /// <summary>
  115.     /// This class encapsulates an XmlSchema manager that loads schemas and associates them with
  116.     /// the XML documents being edited. It also tracks changes to the schemas on disk and reloads
  117.     /// them when necessary.
  118.     /// </summary>
  119.     public class SchemaCache : IXmlSerializable
  120.     {
  121.         //MCorning 10.19.06 Added event so New Menu can populate submenu with nsuri values
  122.         public event EventHandler Changed;
  123.         private IServiceProvider site;
  124.         // targetNamespace -> CacheEntry
  125.         Dictionary<string, CacheEntry> namespaceMap = new Dictionary<string, CacheEntry>();
  126.         // sourceUri -> CacheEntry
  127.         Dictionary<Uri, CacheEntry> uriMap = new Dictionary<Uri, CacheEntry>();
  128.         PersistentFileNames pfn = new PersistentFileNames();
  129.         public SchemaCache(IServiceProvider site) {
  130.             this.site = site;
  131.         }
  132.         void FireOnChanged()
  133.         {
  134.             if (null!=this.Changed  )
  135.             {
  136.                 this.Changed(this, EventArgs.Empty);
  137.             }
  138.         }
  139.         public void Clear() {
  140.             namespaceMap.Clear();
  141.             uriMap.Clear();
  142.         }
  143.         public IList<CacheEntry> GetSchemas() {
  144.             List<CacheEntry> list = new List<CacheEntry>();
  145.             foreach (CacheEntry ce in namespaceMap.Values) {
  146.                 CacheEntry e = ce;
  147.                 while (e != null) {
  148.                     list.Add(e);
  149.                     e = e.Next;
  150.                 }
  151.             }
  152.             return list;
  153.         }
  154.         public CacheEntry Add(string nsuri, Uri uri, bool disabled) {
  155.             if (nsuri == null) nsuri = "";
  156.             CacheEntry existing = null;
  157.             CacheEntry e = null;
  158.             if (namespaceMap.ContainsKey(nsuri)) {
  159.                 existing = namespaceMap[nsuri];
  160.                 e = existing.FindByUri(uri);                
  161.             }
  162.             if (e == null) {
  163.                 e = new CacheEntry();
  164.                 e.Location = uri;
  165.                 e.TargetNamespace = nsuri;
  166.                 if (existing != null) {
  167.                     existing.Add(e);
  168.                 } else {
  169.                     namespaceMap[nsuri] = e;
  170.                 }
  171.             }
  172.             e.Disabled = disabled;
  173.             if (uriMap.ContainsKey(uri)) {
  174.                 CacheEntry oe = (CacheEntry)uriMap[uri];
  175.                 if (oe != e) {
  176.                     // target namespace must have changed!
  177.                     nsuri = oe.TargetNamespace;
  178.                     if (nsuri == null) nsuri = "";
  179.                     if (namespaceMap.ContainsKey(nsuri)) {
  180.                         namespaceMap.Remove(nsuri);
  181.                     }
  182.                 }
  183.             }
  184.             uriMap[uri] = e;
  185.             this.FireOnChanged();
  186.             return e;
  187.         }
  188.         public CacheEntry Add(XmlSchema s) {
  189.             CacheEntry e = Add(s.TargetNamespace, new Uri(s.SourceUri), false);
  190.             if (e.Schema != null) {
  191.                 e.Schema = s;
  192.             }
  193.             return e;
  194.         }
  195.         public void Remove(CacheEntry ce) {
  196.             Remove(ce.Location);
  197.         }
  198.         public void Remove(Uri uri) {
  199.             if (uriMap.ContainsKey(uri)) {
  200.                 CacheEntry e = uriMap[uri];
  201.                 uriMap.Remove(uri);
  202.                 string key = e.TargetNamespace;
  203.                 if (namespaceMap.ContainsKey(key)) {
  204.                     CacheEntry head = namespaceMap[key];
  205.                     CacheEntry newHead = head.RemoveUri(uri);
  206.                     if (newHead == null) {
  207.                         namespaceMap.Remove(key);
  208.                     } else if (newHead != head) {
  209.                         namespaceMap[key] = newHead;
  210.                     }
  211.                     this.FireOnChanged();
  212.                 }
  213.             }
  214.         }
  215.         public void Remove(string filename) {
  216.             Uri uri = new Uri(filename);
  217.             Remove(uri);
  218.         }
  219.         public void Remove(XmlSchema s) {
  220.             Remove(s.SourceUri);
  221.         }        
  222.         public CacheEntry FindSchemasByNamespace(string targetNamespace) {
  223.             if (namespaceMap.ContainsKey(targetNamespace)) {
  224.                 return namespaceMap[targetNamespace];                
  225.             }
  226.             return null;
  227.         }
  228.         public CacheEntry FindSchemaByUri(string sourceUri) {
  229.             if (string.IsNullOrEmpty(sourceUri)) return null;
  230.             return FindSchemaByUri(new Uri(sourceUri));
  231.         }
  232.         public CacheEntry FindSchemaByUri(Uri uri) {
  233.             if (uriMap.ContainsKey(uri)) {
  234.                 return uriMap[uri];
  235.             }
  236.             return null;
  237.         }
  238.         public XmlResolver Resolver {
  239.             get {
  240.                 return new SchemaResolver(this, site);
  241.             }
  242.         }
  243.         public XmlSchemaType FindSchemaType(XmlQualifiedName qname) {
  244.             string tns = qname.Namespace == null ? "" : qname.Namespace;
  245.             CacheEntry e = this.FindSchemasByNamespace(tns);
  246.             if (e == null) return null;
  247.             while (e != null) {
  248.                 XmlSchema s = e.Schema;
  249.                 if (s != null) {
  250.                     XmlSchemaObject so = s.SchemaTypes[qname];
  251.                     if (so is XmlSchemaType)
  252.                         return (XmlSchemaType)so;
  253.                 }
  254.                 e = e.Next;
  255.             }
  256.             return null;
  257.         }
  258.         public IIntellisenseList GetExpectedValues(XmlSchemaType si) {
  259.             if (si == null) return null;
  260.             XmlIntellisenseList list = new XmlIntellisenseList();
  261.             GetExpectedValues(si, list);
  262.             return list;
  263.         }
  264.         public void GetExpectedValues(XmlSchemaType si, XmlIntellisenseList list) {
  265.             if (si == null) return;
  266.             if (si is XmlSchemaSimpleType) {
  267.                 XmlSchemaSimpleType st = (XmlSchemaSimpleType)si;
  268.                 GetExpectedValues(st, list);
  269.             } else if (si is XmlSchemaComplexType) {
  270.                 XmlSchemaComplexType ct = (XmlSchemaComplexType)si;
  271.                 if (ct.ContentModel is XmlSchemaComplexContent) {
  272.                     XmlSchemaComplexContent cc = (XmlSchemaComplexContent)ct.ContentModel;
  273.                     if (cc.Content is XmlSchemaComplexContentExtension) {
  274.                         XmlSchemaComplexContentExtension ce = (XmlSchemaComplexContentExtension)cc.Content;
  275.                         GetExpectedValues(GetTypeInfo(ce.BaseTypeName), list);
  276.                     } else if (cc.Content is XmlSchemaComplexContentRestriction) {
  277.                         XmlSchemaComplexContentRestriction cr = (XmlSchemaComplexContentRestriction)cc.Content;
  278.                         GetExpectedValues(GetTypeInfo(cr.BaseTypeName), list);
  279.                     }
  280.                 } else if (ct.ContentModel is XmlSchemaSimpleContent) {
  281.                     XmlSchemaSimpleContent sc = (XmlSchemaSimpleContent)ct.ContentModel;
  282.                     if (sc.Content is XmlSchemaSimpleContentExtension) {
  283.                         XmlSchemaSimpleContentExtension ce = (XmlSchemaSimpleContentExtension)sc.Content;
  284.                         GetExpectedValues(GetTypeInfo(ce.BaseTypeName), list);
  285.                     } else if (sc.Content is XmlSchemaSimpleContentRestriction) {
  286.                         XmlSchemaSimpleContentRestriction cr = (XmlSchemaSimpleContentRestriction)sc.Content;
  287.                         GetExpectedValues(GetTypeInfo(cr.BaseTypeName), list);
  288.                     }
  289.                 }
  290.             }
  291.             return;
  292.         }
  293.         XmlSchemaType GetTypeInfo(XmlQualifiedName qname) {
  294.             return this.FindSchemaType(qname);
  295.         }
  296.         void GetExpectedValues(XmlSchemaSimpleType st, XmlIntellisenseList list) {
  297.             if (st == null) return;
  298.             if (st.Datatype != null) {
  299.                 switch (st.Datatype.TypeCode) {
  300.                     case XmlTypeCode.Language:
  301.                         foreach (CultureInfo ci in CultureInfo.GetCultures(CultureTypes.AllCultures)) {
  302.                             list.Add(ci.Name, ci.DisplayName);
  303.                         }
  304.                         list.Sort();
  305.                         break;
  306.                     case XmlTypeCode.Boolean:
  307.                         list.Add("0", null);
  308.                         list.Add("1", null);
  309.                         list.Add("true", null);
  310.                         list.Add("false", null);
  311.                         break;
  312.                 }
  313.             }
  314.             if (st.Content is XmlSchemaSimpleTypeList) {
  315.                 XmlSchemaSimpleTypeList ce = (XmlSchemaSimpleTypeList)st.Content;
  316.                 GetExpectedValues(ce.ItemType, list);
  317.             } else if (st.Content is XmlSchemaSimpleTypeUnion) {
  318.                 XmlSchemaSimpleTypeUnion cr = (XmlSchemaSimpleTypeUnion)st.Content;
  319.                 if (cr.BaseMemberTypes != null) {
  320.                     foreach (XmlSchemaSimpleType bt in cr.BaseMemberTypes) {
  321.                         GetExpectedValues(bt, list);
  322.                     }
  323.                 }
  324.             } else if (st.Content is XmlSchemaSimpleTypeRestriction) {
  325.                 XmlSchemaSimpleTypeRestriction cr = (XmlSchemaSimpleTypeRestriction)st.Content;
  326.                 GetExpectedValues(FindSchemaType(cr.BaseTypeName), list);
  327.                 foreach (XmlSchemaFacet f in cr.Facets) {
  328.                     if (f is XmlSchemaEnumerationFacet) {
  329.                         XmlSchemaEnumerationFacet ef = (XmlSchemaEnumerationFacet)f;
  330.                         list.Add(ef.Value, GetAnnotation(ef, SchemaCache.AnnotationNode.Tooltip));
  331.                     }
  332.                 }                
  333.             }
  334.             return;
  335.         }
  336.         public enum AnnotationNode { Default, Suggestion, Tooltip  }
  337.         public static XmlSchemaDocumentation GetDocumentation(XmlSchemaAnnotated a) {
  338.             XmlSchemaAnnotation ann = a.Annotation;
  339.             if (ann == null) return null;
  340.             foreach (XmlSchemaObject o in ann.Items) {
  341.                 // search for xs:documentation nodes
  342.                 XmlSchemaDocumentation doc = o as XmlSchemaDocumentation;
  343.                 if (doc != null) return doc;
  344.             }
  345.             return null;
  346.         }
  347.         public static string GetAnnotation(XmlSchemaAnnotated a, AnnotationNode node) {
  348.             XmlSchemaAnnotation ann = a.Annotation;
  349.             if (ann == null) return null;
  350.             string filter = node.ToString().ToLowerInvariant();
  351.             if (filter == "default") filter = "";
  352.             string result = GetMarkup(ann, filter);
  353.             if (!string.IsNullOrEmpty(result)) return result;
  354.             return GetMarkup(ann, null);
  355.         }
  356.         static string GetMarkup(XmlSchemaAnnotation ann, string filter) {
  357.             StringBuilder sb = new StringBuilder();
  358.             foreach (XmlSchemaObject o in ann.Items) {
  359.                 // for xs:documentation nodes
  360.                 if (o is XmlSchemaDocumentation) {
  361.                     XmlSchemaDocumentation d = (XmlSchemaDocumentation)o;
  362.                     XmlNode[] ma = d.Markup;
  363.                     if (ma != null) {
  364.                         // if we only have the xs:documentation node (no markup)...
  365.                         foreach (XmlNode n in ma) {
  366.                             if (string.IsNullOrEmpty(filter) || 
  367.                                 string.Compare(filter, n.LocalName, StringComparison.InvariantCultureIgnoreCase)==0) {
  368.                                 sb.Append(n.InnerText);
  369.                             }
  370.                         }
  371.                     }
  372.                 }
  373.             }
  374.             return sb.ToString();
  375.         }
  376.         #region IXmlSerializable Members
  377.         public XmlSchema GetSchema() {
  378.             return null;
  379.         }
  380.         public void ReadXml(XmlReader r) {
  381.             this.Clear();
  382.             if (r.IsEmptyElement) return;
  383.             while (r.Read() && r.NodeType != XmlNodeType.EndElement) {
  384.                 if (r.NodeType == XmlNodeType.Element) {
  385.                     string nsuri = r.GetAttribute("nsuri");
  386.                     bool disabled = false;
  387.                     string s = r.GetAttribute("disabled");
  388.                     if (!string.IsNullOrEmpty(s)) {
  389.                         bool.TryParse(s, out disabled);
  390.                     }
  391.                     string filename = r.ReadString();
  392.                     this.Add(nsuri, pfn.GetAbsoluteFilename(filename), disabled);
  393.                 }
  394.             }
  395.         }
  396.         public void WriteXml(XmlWriter w) {
  397.             try {
  398.                 foreach (CacheEntry e in this.GetSchemas()) {
  399.                     string path = pfn.GetPersistentFileName(e.Location);
  400.                     if (path != null) {
  401.                         w.WriteStartElement("Schema");
  402.                         string uri = e.TargetNamespace;
  403.                         if (uri == null) uri = "";
  404.                         w.WriteAttributeString("nsuri", uri);
  405.                         if (e.Disabled) {
  406.                             w.WriteAttributeString("disabled", "true");
  407.                         }
  408.                         w.WriteString(path);
  409.                         w.WriteEndElement();
  410.                     }
  411.                 }
  412.             } catch (Exception x) {
  413.                 Console.WriteLine(x.Message);
  414.             }
  415.         }
  416.         #endregion
  417.     }
  418.     public class SchemaResolver : XmlProxyResolver {
  419.         SchemaCache cache;
  420.         ValidationEventHandler handler;
  421.         public SchemaResolver(SchemaCache cache, IServiceProvider site) : base(site) {
  422.             this.cache = cache;
  423.         }
  424.         public ValidationEventHandler Handler {
  425.             get { return handler; }
  426.             set { handler = value; }
  427.         }
  428.         public override object GetEntity(Uri absoluteUri, string role, Type ofObjectToReturn) {
  429.             CacheEntry ce = cache.FindSchemaByUri(absoluteUri);
  430.             if (ce != null && ce.HasUpToDateSchema) return ce.Schema;
  431.             Stream stm = base.GetEntity(absoluteUri, role, typeof(Stream)) as Stream;
  432.             using (stm) {
  433.                 if (stm != null) {
  434.                     XmlSchema s = XmlSchema.Read(stm, handler);
  435.                     s.SourceUri = absoluteUri.AbsoluteUri;
  436.                     if (ce != null) {
  437.                         ce.Schema = s;
  438.                     } else {
  439.                         cache.Add(s);
  440.                     }
  441.                     return s;
  442.                 }
  443.             }
  444.             return null;
  445.         }
  446.     }
  447. }