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

xml/soap/webservice

开发平台:

Visual C++

  1. using System;
  2. using System.Text;
  3. using System.Xml;
  4. using System.Xml.Schema;
  5. using System.ComponentModel;
  6. using System.Collections;
  7. using System.Collections.Generic;
  8. using System.Reflection;
  9. using System.IO;
  10. namespace XmlNotepad {
  11.     public class XmlIntellisenseProvider : IIntellisenseProvider, IDisposable {
  12.         Hashtable typeCache = new Hashtable();
  13.         XmlCache model;
  14.         XmlTreeNode node;
  15.         XmlNode xn;
  16.         Checker checker;
  17.         ISite site;
  18.         const string vsIntellisense = "http://schemas.microsoft.com/Visual-Studio-Intellisense";
  19.         public XmlIntellisenseProvider(XmlCache model, ISite site) {
  20.             this.model = model;
  21.             this.site = site;
  22.         }
  23.         public virtual Uri BaseUri {
  24.             get { return this.model != null ? this.model.Location : null;  }
  25.         }
  26.         public virtual bool IsNameEditable { get { return true; } }
  27.         public virtual bool IsValueEditable { get { return true; } }
  28.         public void SetContextNode(TreeNode node) {
  29.             this.ContextNode = node;
  30.             OnContextChanged();
  31.         }
  32.         public TreeNode ContextNode {
  33.             get { return node; }
  34.             set { node = value as XmlTreeNode; }
  35.         }
  36.         public virtual void OnContextChanged() {
  37.             this.checker = null;
  38.            
  39.             // Get intellisense for elements and attributes
  40.             if (this.node.NodeType == XmlNodeType.Element ||
  41.                 this.node.NodeType == XmlNodeType.Attribute ||
  42.                 this.node.NodeType == XmlNodeType.Text ||
  43.                 this.node.NodeType == XmlNodeType.CDATA) {
  44.                 XmlTreeNode elementNode = GetClosestElement(this.node);
  45.                 if (elementNode != null && elementNode.NodeType == XmlNodeType.Element) {
  46.                     this.xn = elementNode.Node;
  47.                     if (xn is XmlElement) {
  48.                         this.checker = new Checker((XmlElement)xn,
  49.                             elementNode == this.node.Parent ? IntellisensePosition.FirstChild :
  50.                             (this.node.Node == null ? IntellisensePosition.AfterNode : IntellisensePosition.OnNode)
  51.                             );
  52.                         this.checker.ValidateContext(model);
  53.                     }
  54.                 }
  55.             }
  56.         }
  57.         static XmlTreeNode GetClosestElement(XmlTreeNode treeNode) {
  58.             XmlTreeNode element = treeNode.Parent as XmlTreeNode;
  59.             if (treeNode.Parent != null) {
  60.                 foreach (XmlTreeNode child in treeNode.Parent.Nodes) {
  61.                     if (child.Node != null && child.NodeType == XmlNodeType.Element) {
  62.                         element = child;
  63.                     }
  64.                     if (child == treeNode)
  65.                         break;
  66.                 }
  67.             }
  68.             return element;
  69.         }
  70.         public virtual XmlSchemaType GetSchemaType() {
  71.             XmlSchemaInfo info = GetSchemaInfo();
  72.             return info != null ? info.SchemaType : null;
  73.         }
  74.         XmlSchemaInfo GetSchemaInfo() {
  75.             XmlTreeNode tn = node;
  76.             if (tn.NodeType == XmlNodeType.Text ||
  77.                 tn.NodeType == XmlNodeType.CDATA) {
  78.                 tn = (XmlTreeNode)tn.Parent;
  79.             }
  80.             if (tn == null) return null;
  81.             XmlNode xn = tn.Node;
  82.             if (xn != null && model != null) {
  83.                 XmlSchemaInfo info = model.GetTypeInfo(xn);
  84.                 return info;
  85.             }
  86.             return null;
  87.         }
  88.         public virtual string GetDefaultValue() {
  89.             XmlSchemaInfo info = GetSchemaInfo();
  90.             if (info != null) {
  91.                 if (info.SchemaAttribute != null) {
  92.                     return info.SchemaAttribute.DefaultValue;
  93.                 } else if (info.SchemaElement != null) {
  94.                     return info.SchemaElement.DefaultValue;
  95.                 }   
  96.             }
  97.             return null;
  98.         }
  99.         public virtual IIntellisenseList GetExpectedValues() {
  100.             XmlSchemaType type = GetSchemaType();
  101.             if (type != null) {
  102.                 return model.SchemaCache.GetExpectedValues(type);
  103.             }
  104.             if (node != null && node.Node != null) {
  105.                 XmlNode xn = node.Node;
  106.                 if (xn.NodeType == XmlNodeType.Attribute && xn.NamespaceURI == "http://www.w3.org/2000/xmlns/") {
  107.                     XmlNode parent = ((XmlTreeNode)node.Parent).Node;
  108.                     return GetNamespaceList(parent);
  109.                 }
  110.             }            
  111.             return null;
  112.         }
  113.         public XmlIntellisenseList GetNamespaceList(XmlNode node) {
  114.             XmlIntellisenseList list = new XmlIntellisenseList();
  115.             list.IsOpen = true;
  116.             Dictionary<string, string> map = new Dictionary<string, string>();
  117.             foreach (XmlNode a in node.SelectNodes("namespace::*")) {
  118.                 string tns = a.Value;
  119.                 list.Add(tns, null);
  120.             }
  121.             foreach (CacheEntry ce in this.model.SchemaCache.GetSchemas()) {
  122.                 if (ce.Schema == null) continue;
  123.                 string tns = ce.Schema.TargetNamespace;
  124.                 list.Add(tns, null);
  125.             }
  126.             list.Add("http://www.w3.org/2001/XMLSchema-instance", null);
  127.             list.Add("http://www.w3.org/2001/XMLSchema", null);
  128.             list.Sort();
  129.             return list;
  130.         }
  131.         public virtual IIntellisenseList GetExpectedNames() {
  132.             if (checker != null) {
  133.                 XmlIntellisenseList list = new XmlIntellisenseList();
  134.                 if (node.NodeType == XmlNodeType.Attribute) {
  135.                     XmlSchemaAttribute[] expected = checker.GetExpectedAttributes();
  136.                     if (expected != null) {
  137.                         foreach (XmlSchemaAttribute a in expected) {
  138.                             list.Add(GetQualifiedName(a), SchemaCache.GetAnnotation(a, SchemaCache.AnnotationNode.Tooltip));
  139.                         }
  140.                     }
  141.                 } else {
  142.                     XmlSchemaParticle[] particles = checker.GetExpectedParticles();
  143.                     if (particles != null) {
  144.                         foreach (XmlSchemaParticle p in particles) {
  145.                             if (p is XmlSchemaElement) {
  146.                                 list.Add(GetQualifiedName((XmlSchemaElement)p), SchemaCache.GetAnnotation(p, SchemaCache.AnnotationNode.Tooltip));
  147.                             } else {
  148.                                 // todo: expand XmlSchemaAny particles.
  149.                                 list.IsOpen = true;
  150.                             }
  151.                         }
  152.                     }
  153.                 }
  154.                 list.Sort();
  155.                 return list;
  156.             }
  157.             return null;
  158.         }
  159.         static string GetUnhandledAttribute(XmlAttribute[] attributes, string localName, string nsuri) {
  160.             if (attributes != null) {
  161.                 foreach (XmlAttribute a in attributes) {
  162.                     if (a.LocalName == localName && a.NamespaceURI == nsuri) {
  163.                         return a.Value;
  164.                     }
  165.                 }
  166.             }
  167.             return null;
  168.         }
  169.         public string GetIntellisenseAttribute(string name) {
  170.             string value = null;
  171.             XmlSchemaInfo info = GetSchemaInfo();
  172.             if (info != null) {
  173.                 if (info.SchemaElement != null) {
  174.                     value = GetUnhandledAttribute(info.SchemaElement.UnhandledAttributes, name, vsIntellisense);
  175.                 }
  176.                 if (info.SchemaAttribute != null) {
  177.                     value = GetUnhandledAttribute(info.SchemaAttribute.UnhandledAttributes, name, vsIntellisense);
  178.                 }
  179.                 if (value == null && info.SchemaType != null) {
  180.                     value = GetUnhandledAttribute(info.SchemaType.UnhandledAttributes, name, vsIntellisense);
  181.                 }
  182.             }
  183.             return value;
  184.         }
  185.         public virtual IXmlBuilder Builder {
  186.             get {
  187.                 string typeName = GetIntellisenseAttribute("builder");
  188.                 if (!string.IsNullOrEmpty(typeName)) {
  189.                     IXmlBuilder builder = ConstructType(typeName) as IXmlBuilder;
  190.                     if (builder != null) builder.Owner = this;
  191.                     return builder;
  192.                 }
  193.                 // Some default builders.
  194.                 XmlSchemaType type = GetSchemaType();
  195.                 if (type != null) {
  196.                     switch (type.TypeCode) {
  197.                         case XmlTypeCode.AnyUri:
  198.                             IXmlBuilder builder = ConstructType("XmlNotepad.UriBuilder") as IXmlBuilder;
  199.                             if (builder != null) builder.Owner = this;
  200.                             return builder;
  201.                     }
  202.                 }
  203.                 return null;
  204.             }
  205.         }
  206.         public virtual IXmlEditor Editor {
  207.             get {
  208.                 string typeName = GetIntellisenseAttribute("editor");
  209.                 if (!string.IsNullOrEmpty(typeName)) {
  210.                     return ConstructType(typeName) as IXmlEditor;
  211.                 }
  212.                 // Some default editors.
  213.                 XmlSchemaType type = GetSchemaType();
  214.                 if (type != null) {
  215.                     switch (type.TypeCode) {
  216.                         case XmlTypeCode.Date:
  217.                         case XmlTypeCode.DateTime:
  218.                         case XmlTypeCode.Time:
  219.                             IXmlEditor editor = ConstructType("XmlNotepad.DateTimeEditor") as IXmlEditor;
  220.                             if (editor != null) editor.Owner = this;
  221.                             return editor;
  222.                     }
  223.                 }
  224.                 return null;
  225.             }
  226.         }
  227.         object ConstructType(string typeName) {
  228.             // Cache the objects so they can preserve user state.
  229.             if (typeCache.ContainsKey(typeName))
  230.                 return typeCache[typeName];
  231.             Type t = Type.GetType(typeName);
  232.             if (t == null) {
  233.                 // perhaps there's an associated assembly we need to load.
  234.                 string assembly = GetIntellisenseAttribute("assembly");
  235.                 if (!string.IsNullOrEmpty(assembly)) {
  236.                     try {
  237.                         string[] parts = assembly.Split(',');
  238.                         string newdir = Path.GetDirectoryName(this.GetType().Assembly.Location);
  239.                         Uri uri = new Uri(newdir+"\");
  240.                         Uri resolved =new Uri(uri, parts[0]+".dll");
  241.                         Assembly a;
  242.                         if (resolved.IsFile && File.Exists(resolved.LocalPath)) {
  243.                             a = Assembly.LoadFrom(resolved.LocalPath);
  244.                         } else {
  245.                             a = Assembly.Load(assembly);
  246.                         }
  247.                         if (a != null) {
  248.                             t = a.GetType(typeName);
  249.                         }
  250.                     } catch (Exception e) {
  251.                         System.Windows.Forms.MessageBox.Show(string.Format(SR.AssemblyLoadError, assembly, e.Message),
  252.                         SR.AssemblyLoadCaption, System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Error);
  253.                     }
  254.                 }
  255.             }
  256.             if (t != null) {
  257.                 ConstructorInfo ci = t.GetConstructor(new Type[0]);
  258.                 if (ci != null) {
  259.                     object result = ci.Invoke(new Object[0]);
  260.                     if (result != null) {
  261.                         typeCache[typeName] = result;
  262.                         return result;
  263.                     }
  264.                 }
  265.             }
  266.             return null;
  267.         }
  268.         public string GetQualifiedName(XmlSchemaAttribute a) {
  269.             string name = a.Name;
  270.             string nsuri = null;
  271.             if (a.QualifiedName != null) {
  272.                 name = a.QualifiedName.Name;
  273.                 nsuri = a.QualifiedName.Namespace;
  274.             } else if (a.RefName != null) {
  275.                 name = a.QualifiedName.Name;
  276.                 nsuri = a.QualifiedName.Namespace;
  277.             } else {
  278.                 nsuri = GetSchema(a).TargetNamespace;
  279.             }
  280.             if (!string.IsNullOrEmpty(nsuri) && this.xn != null) {
  281.                 string prefix = this.xn.GetPrefixOfNamespace(nsuri);
  282.                 if (!string.IsNullOrEmpty(prefix)) {
  283.                     return prefix + ":" + name;
  284.                 }
  285.             }
  286.             return name;
  287.         }
  288.         public string GetQualifiedName(XmlSchemaElement e) {
  289.             string name = e.Name;
  290.             string nsuri = null;
  291.             if (e.QualifiedName != null) {
  292.                 name = e.QualifiedName.Name;
  293.                 nsuri = e.QualifiedName.Namespace;
  294.             } else if (e.RefName != null) {
  295.                 name = e.QualifiedName.Name;
  296.                 nsuri = e.QualifiedName.Namespace;
  297.             } else {
  298.                 nsuri = GetSchema(e).TargetNamespace;
  299.             }
  300.             if (!string.IsNullOrEmpty(nsuri) && this.xn != null) {
  301.                 string prefix = this.xn.GetPrefixOfNamespace(nsuri);
  302.                 if (!string.IsNullOrEmpty(prefix)) {
  303.                     return prefix + ":" + name;
  304.                 }
  305.             }
  306.             return name;
  307.         }
  308.         XmlSchema GetSchema(XmlSchemaObject o) {
  309.             if (o == null) return null;
  310.             if (o is XmlSchema) return (XmlSchema)o;
  311.             return GetSchema(o.Parent);
  312.         }
  313.         ~XmlIntellisenseProvider() {
  314.             Dispose(false);
  315.         }
  316.         #region IDisposable Members
  317.         public void Dispose() {
  318.             Dispose(true);
  319.         }
  320.         #endregion
  321.         protected virtual void Dispose(bool disposing) {
  322.             if (this.typeCache != null) {
  323.                 foreach (object value in this.typeCache.Values) {
  324.                     IDisposable d = value as IDisposable;
  325.                     if (d != null) d.Dispose();
  326.                 }
  327.                 this.typeCache = null;
  328.             }
  329.         }
  330.     }
  331.     public class XmlIntellisenseList : IIntellisenseList {
  332.         class Entry {
  333.             public string name;
  334.             public string tooltip;
  335.             public Entry(string name, string tip) {
  336.                 this.name = name;
  337.                 this.tooltip = string.IsNullOrEmpty(tip) ? null : tip;
  338.             }
  339.         }
  340.         class EntryComparer : IComparer<Entry> {
  341.             public int Compare(Entry x, Entry y) {
  342.                 return string.Compare(x.name, y.name);
  343.             }
  344.         }
  345.         Dictionary<string, Entry> unique = new Dictionary<string, Entry>();
  346.         List<Entry> items = new List<Entry>();
  347.         bool isOpen;
  348.         public XmlIntellisenseList() {
  349.         }
  350.         public bool IsOpen {
  351.             get { return this.isOpen; }
  352.             set { this.isOpen = value; }
  353.         }
  354.         public void Add(string s, string tip) {
  355.             if (!string.IsNullOrEmpty(s) && !unique.ContainsKey(s)) {
  356.                 Entry e = new Entry(s, tip);
  357.                 unique[s] = e;
  358.                 items.Add(e);
  359.             }
  360.         }
  361.         public void Sort() {
  362.             items.Sort(new EntryComparer());
  363.         }
  364.         public int Count {
  365.             get { return items.Count; }
  366.         }
  367.         public string GetValue(int i) {
  368.             return items[i].name;
  369.         }
  370.         public string GetTooltip(int i) {
  371.             return items[i].tooltip;
  372.         }
  373.     }
  374. }