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

xml/soap/webservice

开发平台:

Visual C++

  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using System.Text;
  5. using System.Xml;
  6. using System.Xml.Schema;
  7. using System.Diagnostics;
  8. using System.Reflection;
  9. using System.ComponentModel;
  10. using System.Globalization;
  11. namespace XmlNotepad {
  12.     public abstract class ErrorHandler {
  13.         public abstract void HandleError(Severity sev, string reason, string filename, int line, int col, object data);
  14.     }
  15.     public enum IntellisensePosition { OnNode, AfterNode, FirstChild }
  16.     
  17.     public class Checker {
  18.         XmlCache cache;
  19.         XmlSchemaValidator validator;
  20.         XmlSchemaInfo info;
  21.         ErrorHandler eh;
  22.         MyXmlNamespaceResolver nsResolver;
  23.         Uri baseUri;
  24.         Dictionary<XmlNode, XmlSchemaInfo> typeInfo = new Dictionary<XmlNode, XmlSchemaInfo>();
  25.         XmlSchemaAttribute[] expectedAttributes;
  26.         XmlSchemaParticle[] expectedParticles;
  27.         XmlElement node;
  28.         Hashtable parents;
  29.         IntellisensePosition position;
  30.          internal const int SurHighStart = 0xd800;
  31.         internal const int SurHighEnd = 0xdbff;
  32.         internal const int SurLowStart = 0xdc00;
  33.         internal const int SurLowEnd = 0xdfff;
  34.         // Construct a checker for getting expected information about the given element.
  35.         public Checker(XmlElement node, IntellisensePosition position) {
  36.             this.node = node;
  37.             this.position = position;
  38.             parents = new Hashtable();
  39.             XmlNode p = node.ParentNode;
  40.             while (p != null) {
  41.                 parents[p] = p;
  42.                 p = p.ParentNode;
  43.             }            
  44.         }
  45.         public Checker(ErrorHandler eh) {
  46.             this.eh = eh;
  47.         }
  48.         public XmlSchemaAttribute[] GetExpectedAttributes() {
  49.             return expectedAttributes;
  50.         }
  51.         public XmlSchemaParticle[] GetExpectedParticles() {
  52.             return expectedParticles;
  53.         }
  54.         public void ValidateContext(XmlCache xcache) {
  55.             this.cache = xcache;
  56.             if (string.IsNullOrEmpty(cache.FileName)) {
  57.                 baseUri = null;
  58.             } else {
  59.                 baseUri = new Uri(new Uri(xcache.FileName), new Uri(".", UriKind.Relative));
  60.             }
  61.             ValidationEventHandler handler = new ValidationEventHandler(OnValidationEvent);
  62.             SchemaResolver resolver = xcache.SchemaResolver as SchemaResolver;
  63.             resolver.Handler = handler;
  64.             XmlDocument doc = xcache.Document;
  65.             this.info = new XmlSchemaInfo();
  66.             this.nsResolver = new MyXmlNamespaceResolver(doc.NameTable);
  67.             XmlSchemaSet set = new XmlSchemaSet();
  68.             // Make sure the SchemaCache is up to date with document.
  69.             SchemaCache sc = xcache.SchemaCache;
  70.             foreach (XmlSchema s in doc.Schemas.Schemas()) {
  71.                 sc.Add(s);
  72.             }
  73.             if (LoadSchemas(doc, set, resolver)) {
  74.                 set.ValidationEventHandler += handler;
  75.                 set.Compile();
  76.             }
  77.             this.validator = new XmlSchemaValidator(doc.NameTable, set, nsResolver,
  78.                 XmlSchemaValidationFlags.AllowXmlAttributes |
  79.                 XmlSchemaValidationFlags.ProcessIdentityConstraints |
  80.                 XmlSchemaValidationFlags.ProcessInlineSchema);
  81.             this.validator.ValidationEventHandler += handler;
  82.             this.validator.XmlResolver = resolver;
  83.             this.validator.Initialize();
  84.             this.nsResolver.Context = doc;
  85.             ValidateContent(doc);
  86.             this.nsResolver.Context = doc;
  87.             this.validator.EndValidation();
  88.         }
  89.         public void Validate(XmlCache xcache) {
  90.             this.ValidateContext(xcache);
  91.             xcache.TypeInfoMap = typeInfo; // save schema type information for intellisense.
  92.         }
  93.         public XmlSchemaInfo GetTypeInfo(XmlNode node) {
  94.             if (node == null) return null;
  95.             XmlSchemaInfo si;
  96.             typeInfo.TryGetValue(node, out si);
  97.             return si;
  98.         }
  99.         
  100.         bool LoadSchemas(XmlDocument doc, XmlSchemaSet set, SchemaResolver resolver) {
  101.             XmlElement root = doc.DocumentElement;
  102.             if (root == null) return false;
  103.             // Give Xsi schemas highest priority.
  104.             bool result = LoadXsiSchemas(doc, set, resolver);
  105.             SchemaCache sc = this.cache.SchemaCache;
  106.             foreach (XmlAttribute a in root.Attributes) {
  107.                 if (a.NamespaceURI == "http://www.w3.org/2000/xmlns/") {
  108.                     string nsuri = a.Value;
  109.                     result |= LoadSchemasForNamespace(set, resolver, sc, nsuri, a);
  110.                 }
  111.             }
  112.             if (string.IsNullOrEmpty(root.NamespaceURI)){
  113.                 result |= LoadSchemasForNamespace(set, resolver, sc, "", root);
  114.             }
  115.             return result;
  116.         }
  117.         private bool LoadSchemasForNamespace(XmlSchemaSet set, SchemaResolver resolver, SchemaCache sc, string nsuri, XmlNode ctx) {
  118.             bool result = false;
  119.             if (set.Schemas(nsuri).Count == 0) {
  120.                 CacheEntry ce = sc.FindSchemasByNamespace(nsuri);
  121.                 while (ce != null) {
  122.                     if (!ce.Disabled){
  123.                         if (!ce.HasUpToDateSchema) {
  124.                             // delay loaded!
  125.                             LoadSchema(set, resolver, ctx, nsuri, ce.Location.AbsoluteUri);
  126.                         } else {
  127.                             set.Add(ce.Schema);
  128.                         }
  129.                         result = true;
  130.                     }
  131.                     ce = ce.Next;
  132.                 }
  133.             }
  134.             return result;
  135.         }
  136.         bool LoadXsiSchemas(XmlDocument doc, XmlSchemaSet set, SchemaResolver resolver) {
  137.             if (doc.DocumentElement == null) return false;
  138.             bool result = false;
  139.             foreach (XmlAttribute a in doc.DocumentElement.Attributes) {
  140.                 if (a.NamespaceURI == "http://www.w3.org/2001/XMLSchema-instance" ) {
  141.                     if (a.LocalName == "noNamespaceSchemaLocation") {
  142.                         string path = a.Value;
  143.                         if (!string.IsNullOrEmpty(path)) {
  144.                             result = LoadSchema(set, resolver, a, "", a.Value);
  145.                         }
  146.                     } else if (a.LocalName == "schemaLocation") {
  147.                         string[] words = a.Value.Split(new char[] { ' ', 't', 'r', 'n' }, StringSplitOptions.RemoveEmptyEntries);
  148.                         for (int i = 0, n = words.Length; i+1 < n; i++) {
  149.                             string nsuri = words[i];
  150.                             string location = words[++i];
  151.                             result |= LoadSchema(set, resolver, a, nsuri, location);
  152.                         }
  153.                     }
  154.                 }
  155.             }
  156.             return result;
  157.         }
  158.         bool LoadSchema(XmlSchemaSet set, SchemaResolver resolver, XmlNode ctx, string nsuri, string filename) {
  159.             try {
  160.                 Uri baseUri = this.baseUri;
  161.                 if (!string.IsNullOrEmpty(ctx.BaseURI)) {
  162.                     baseUri = new Uri(ctx.BaseURI);
  163.                 }
  164.                 Uri resolved;
  165.                 if (baseUri != null) {
  166.                     resolved = new Uri(baseUri, filename);
  167.                 } else {
  168.                     resolved = new Uri(filename, UriKind.RelativeOrAbsolute);
  169.                 }
  170.                 XmlSchema s = resolver.GetEntity(resolved, "", typeof(XmlSchema)) as XmlSchema;
  171.                 if ((s.TargetNamespace+"") != (nsuri+"")) {
  172.                     ReportError(Severity.Warning, SR.TNSMismatch, ctx);
  173.                 } else if (!set.Contains(s)) {
  174.                     set.Add(s);
  175.                     return true;
  176.                 }
  177.             } catch (Exception e) {
  178.                 ReportError(Severity.Warning, string.Format(SR.SchemaLoadError, filename, e.Message), ctx);
  179.             }
  180.             return false;
  181.         }
  182.         void ReportError(Severity sev, string msg, XmlNode ctx) {
  183.             if (eh == null) return;
  184.             int line = 0, col = 0;
  185.             string filename = cache.FileName;
  186.             LineInfo li = cache.GetLineInfo(ctx);
  187.             if (li != null) {
  188.                 line = li.LineNumber;
  189.                 col = li.LinePosition;
  190.                 filename = GetRelative(li.BaseUri);
  191.             }
  192.             eh.HandleError(sev, msg, filename, line, col, ctx);
  193.         }
  194.         void ValidateContent(XmlNode container) {            
  195.             foreach (XmlNode n in container.ChildNodes) {
  196.                 // If we are validating up to a given node for intellisense info, then
  197.                 // we can prune out any nodes that are not connected to the same parent chain.
  198.                 if (parents == null || parents.Contains(n.ParentNode)) {
  199.                     ValidateNode(n);
  200.                 }
  201.                 if (n == this.node) {
  202.                     break; // we're done!
  203.                 }
  204.             }
  205.         }
  206.         void ValidateNode(XmlNode node) {
  207.             XmlElement e = node as XmlElement;
  208.             if (e != null) {
  209.                 ValidateElement(e);
  210.                 return;
  211.             }
  212.             XmlText t = node as XmlText;
  213.             if (t != null) {
  214.                 ValidateText(t);
  215.                 return;
  216.             }
  217.             XmlCDataSection cd = node as XmlCDataSection;
  218.             if (cd != null) {
  219.                 ValidateText(cd);
  220.                 return;
  221.             }
  222.             XmlWhitespace w = node as XmlWhitespace;
  223.             if (w != null) {
  224.                 ValidateWhitespace(w);
  225.                 return;
  226.             }
  227.         }
  228.         XmlSchemaInfo GetInfo() {
  229.             XmlSchemaInfo i = this.info;
  230.             XmlSchemaInfo copy = new XmlSchemaInfo();
  231.             copy.ContentType = i.ContentType;
  232.             copy.IsDefault = i.IsDefault;
  233.             copy.IsNil = i.IsNil;
  234.             copy.MemberType = i.MemberType;
  235.             copy.SchemaAttribute = i.SchemaAttribute;
  236.             copy.SchemaElement = i.SchemaElement;
  237.             copy.SchemaType = i.SchemaType;
  238.             copy.Validity = i.Validity;
  239.             return copy;
  240.         }
  241.         void ValidateElement(XmlElement e) {
  242.             this.nsResolver.Context = e;
  243.             if (this.node == e && position == IntellisensePosition.OnNode) {
  244.                 this.expectedParticles = validator.GetExpectedParticles();
  245.             }
  246.             string xsiType = null;
  247.             string xsiNil = null;
  248.             foreach (XmlAttribute a in e.Attributes) {
  249.                 if (XmlHelpers.IsXsiAttribute(a)) {
  250.                     string name = a.LocalName;
  251.                     if (name == "type") {
  252.                         xsiType = a.Value;
  253.                     } else if (name == "nil") {
  254.                         xsiNil = a.Value;
  255.                     }
  256.                 }
  257.             }
  258.             validator.ValidateElement(e.LocalName, e.NamespaceURI, this.info, xsiType, xsiNil, null, null);
  259.             if (this.info.SchemaType != null) {
  260.                 typeInfo[e] = GetInfo();
  261.             }
  262.             foreach (XmlAttribute a in e.Attributes) {
  263.                 if (!XmlHelpers.IsXmlnsNode(a)) {
  264.                     ValidateAttribute(a);
  265.                 }
  266.             }
  267.             if (this.node == e) {
  268.                 this.expectedAttributes = validator.GetExpectedAttributes();
  269.             }
  270.             this.nsResolver.Context = e;
  271.             validator.ValidateEndOfAttributes(this.info);
  272.             if (this.node == e && position == IntellisensePosition.FirstChild) {
  273.                 this.expectedParticles = validator.GetExpectedParticles();
  274.             }
  275.             if (this.node != e) {
  276.                 ValidateContent(e);
  277.             }
  278.             this.nsResolver.Context = e;            
  279.             validator.ValidateEndElement(this.info);
  280.             if (this.node == e && position == IntellisensePosition.AfterNode) {
  281.                 this.expectedParticles = validator.GetExpectedParticles();
  282.             }
  283.             
  284.         }
  285.         void ValidateText(XmlCharacterData text) {
  286.             this.nsResolver.Context = text;
  287.             CheckCharacters();
  288.             validator.ValidateText(new XmlValueGetter(GetText));
  289.         }
  290.         /// <summary>
  291.         /// We turned off Character checking on the XmlReader so we could load more
  292.         /// XML documents, so here we implement that part of the W3C spec:
  293.         /// [2]    Char    ::=    #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | 
  294.         ///                       [#x10000-#x10FFFF] 
  295.         /// </summary>
  296.         /// <param name="text"></param>
  297.         void CheckCharacters() {
  298.             if (eh == null) return;
  299.             XmlNode node = this.nsResolver.Context;
  300.             if (node == null) return;
  301.             string text = node.InnerText;
  302.             if (text == null) return;
  303.             XmlNode ctx = node.ParentNode;
  304.             if (ctx == null) ctx = node;
  305.             for (int i = 0, n = text.Length; i < n; i++) {
  306.                 char ch = text[i];
  307.                 if ((ch < 20 && ch != 0x9 && ch != 0xa && ch != 0xd) || ch > 0xfffe) {
  308.                     ReportError(Severity.Error, string.Format(SR.InvalidCharacter, ((int)ch).ToString(), i), ctx);
  309.                 } else if (ch >= SurHighStart && ch <= SurHighEnd) {
  310.                     if (i + 1 < n) {
  311.                         char nc = text[i + 1];
  312.                         if (nc < SurLowStart || nc > SurLowEnd) {
  313.                             ReportError(Severity.Error, string.Format(SR.IllegalSurrogatePair, Convert.ToInt32(ch).ToString("x", CultureInfo.CurrentUICulture), Convert.ToInt32(nc).ToString("x", CultureInfo.CurrentUICulture), i), ctx);
  314.                         } else {
  315.                             i++;
  316.                         }
  317.                     }
  318.                 } else if (ch >= 0xd800 && ch < 0xe000) {
  319.                     ReportError(Severity.Error, string.Format(SR.InvalidCharacter, ((int)ch).ToString(), i), ctx);
  320.                 }
  321.             }
  322.         }
  323.         object GetText() {
  324.             return this.nsResolver.Context.InnerText; ;
  325.         }
  326.         void ValidateWhitespace(XmlWhitespace w) {
  327.             this.nsResolver.Context = w; 
  328.             validator.ValidateWhitespace(w.InnerText);
  329.         }
  330.         void ValidateAttribute(XmlAttribute a) {
  331.             this.nsResolver.Context = a;
  332.             CheckCharacters();
  333.             validator.ValidateAttribute(a.LocalName, a.NamespaceURI, a.Value, this.info);
  334.             typeInfo[a] = GetInfo();
  335.         }
  336.         void OnValidationEvent(object sender, ValidationEventArgs e) {
  337.             if (eh != null) {
  338.                 string filename = cache.FileName;
  339.                 int line = 0;
  340.                 int col = 0;
  341.                 XmlNode node = this.nsResolver.Context;
  342.                 Severity sev = e.Severity == XmlSeverityType.Error ? Severity.Error : Severity.Warning;
  343.                 XmlSchemaException se = e.Exception;
  344.                 if (se != null && !string.IsNullOrEmpty(se.SourceUri) ) {
  345.                     filename = GetRelative(se.SourceUri);
  346.                     line = se.LineNumber;
  347.                     col = se.LinePosition;
  348.                 } else {
  349.                     LineInfo li = cache.GetLineInfo(node);
  350.                     if (li != null) {
  351.                         line = li.LineNumber;
  352.                         col = li.LinePosition;
  353.                         filename = GetRelative(li.BaseUri);
  354.                     }
  355.                 }
  356.                 eh.HandleError(sev, e.Message, filename, line, col, node);
  357.             }
  358.         }
  359.         string GetRelative(string s) {
  360.             if (baseUri == null) return s;
  361.             Uri uri = new Uri(s);
  362.             return this.baseUri.MakeRelative(uri);
  363.         }
  364.     }
  365.     internal class MyXmlNamespaceResolver : System.Xml.IXmlNamespaceResolver {
  366.         System.Xml.XmlNameTable nameTable;
  367.         private XmlNode context;
  368.         private string emptyAtom;
  369.         public MyXmlNamespaceResolver(System.Xml.XmlNameTable nameTable) {
  370.             this.nameTable = nameTable;
  371.             this.emptyAtom = nameTable.Add(string.Empty);
  372.         }
  373.         public XmlNode Context {
  374.             get {
  375.                 return this.context;
  376.             }
  377.             set {
  378.                 this.context = value;
  379.             }
  380.         }
  381.         public System.Xml.XmlNameTable NameTable {
  382.             get {
  383.                 return this.nameTable;
  384.             }
  385.         }
  386.         private string Atomized(string s) {
  387.             if (s == null) return null;
  388.             if (s.Length == 0) return this.emptyAtom;
  389.             return this.nameTable.Add(s);
  390.         }
  391.         public string LookupPrefix(string namespaceName, bool atomizedName) {
  392.             string result = null;
  393.             if (context != null) {
  394.                 result = context.GetPrefixOfNamespace(namespaceName);
  395.             }
  396.             return Atomized(result);
  397.         }
  398.         public string LookupPrefix(string namespaceName) {
  399.             string result = null;
  400.             if (context != null) {
  401.                 result = context.GetPrefixOfNamespace(namespaceName);
  402.             }
  403.             return Atomized(result);
  404.         }
  405.         public string LookupNamespace(string prefix, bool atomizedName) {
  406.             return LookupNamespace(prefix);
  407.         }
  408.         public string LookupNamespace(string prefix) {
  409.             string result = null;
  410.             if (context != null) {
  411.                 result = context.GetNamespaceOfPrefix(prefix);
  412.             }            
  413.             return Atomized(result);
  414.         }
  415.         public IDictionary<string, string> GetNamespacesInScope(System.Xml.XmlNamespaceScope scope) {
  416.             Dictionary<string, string> dict = new Dictionary<string, string>();
  417.             if (this.context != null) {
  418.                 foreach (XmlAttribute a in this.context.SelectNodes("namespace::*")) {
  419.                     string nspace = a.InnerText;
  420.                     string prefix = a.Prefix;
  421.                     if (prefix == "xmlns") {
  422.                         prefix = "";
  423.                     }
  424.                     dict[prefix] = nspace;
  425.                 }
  426.             }
  427.             return dict;
  428.         }
  429.     }
  430. }