The Labs \ Source Viewer \ SSCLI \ System.Xml \ NamespaceDeclaration

  1. //------------------------------------------------------------------------------
  2. // <copyright file="XmlNamespaceManager.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. namespace System.Xml
  16. {
  17.    
  18.     using System;
  19.     using System.IO;
  20.     using System.Collections;
  21.     using System.Diagnostics;
  22.     using System.Collections.Generic;
  23.    
  24.     public class XmlNamespaceManager : IXmlNamespaceResolver, IEnumerable
  25.     {
  26.         static IXmlNamespaceResolver s_EmptyResolver;
  27.        
  28.         struct NamespaceDeclaration
  29.         {
  30.             public string prefix;
  31.             public string uri;
  32.             public int scopeId;
  33.             public int previousNsIndex;
  34.            
  35.             public void Set(string prefix, string uri, int scopeId, int previousNsIndex)
  36.             {
  37.                 this.prefix = prefix;
  38.                 this.uri = uri;
  39.                 this.scopeId = scopeId;
  40.                 this.previousNsIndex = previousNsIndex;
  41.             }
  42.         }
  43.        
  44.         // array with namespace declarations
  45.         NamespaceDeclaration[] nsdecls;
  46.        
  47.         // index of last declaration
  48.         int lastDecl = 0;
  49.        
  50.         // name table
  51.         XmlNameTable nameTable;
  52.        
  53.         // ID (depth) of the current scope
  54.         int scopeId;
  55.        
  56.         // hash table for faster lookup when there is lots of namespaces
  57.         Dictionary<string, int> hashTable;
  58.         bool useHashtable;
  59.        
  60.         // atomized prefixes for "xml" and "xmlns"
  61.         string xml;
  62.         string xmlNs;
  63.        
  64.         // Constants
  65.         const int MinDeclsCountForHashtable = 16;
  66.        
  67.         static internal IXmlNamespaceResolver EmptyResolver {
  68.             get {
  69.                 if (s_EmptyResolver == null) {
  70.                     // no locking; the empty resolver is immutable so it's not a problem that it may get initialized more than once
  71.                     s_EmptyResolver = new XmlNamespaceManager(new NameTable());
  72.                 }
  73.                 return s_EmptyResolver;
  74.             }
  75.         }
  76.        
  77.         internal XmlNamespaceManager()
  78.         {
  79.         }
  80.        
  81.         public XmlNamespaceManager(XmlNameTable nameTable)
  82.         {
  83.             this.nameTable = nameTable;
  84.             xml = nameTable.Add("xml");
  85.             xmlNs = nameTable.Add("xmlns");
  86.            
  87.             nsdecls = new NamespaceDeclaration[8];
  88.             string emptyStr = nameTable.Add(string.Empty);
  89.             nsdecls[0].Set(emptyStr, emptyStr, -1, -1);
  90.             nsdecls[1].Set(xmlNs, nameTable.Add(XmlReservedNs.NsXmlNs), -1, -1);
  91.             nsdecls[2].Set(xml, nameTable.Add(XmlReservedNs.NsXml), 0, -1);
  92.             lastDecl = 2;
  93.             scopeId = 1;
  94.         }
  95.        
  96.         public virtual XmlNameTable NameTable {
  97.             get { return nameTable; }
  98.         }
  99.        
  100.         public virtual string DefaultNamespace {
  101.             get {
  102.                 string defaultNs = LookupNamespace(string.Empty);
  103.                 return (defaultNs == null) ? string.Empty : defaultNs;
  104.             }
  105.         }
  106.        
  107.         public virtual void PushScope()
  108.         {
  109.             scopeId++;
  110.         }
  111.        
  112.         public virtual bool PopScope()
  113.         {
  114.             int decl = lastDecl;
  115.             if (scopeId == 1) {
  116.                 return false;
  117.             }
  118.             while (nsdecls[decl].scopeId == scopeId) {
  119.                 if (useHashtable) {
  120.                     hashTable[nsdecls[decl].prefix] = nsdecls[decl].previousNsIndex;
  121.                 }
  122.                 decl--;
  123.                 Debug.Assert(decl >= 2);
  124.             }
  125.             lastDecl = decl;
  126.             scopeId--;
  127.             return true;
  128.         }
  129.        
  130.         public virtual void AddNamespace(string prefix, string uri)
  131.         {
  132.             if (uri == null)
  133.                 throw new ArgumentNullException("uri");
  134.            
  135.             if (prefix == null)
  136.                 throw new ArgumentNullException("prefix");
  137.            
  138.             prefix = nameTable.Add(prefix);
  139.             uri = nameTable.Add(uri);
  140.            
  141.             if ((Ref.Equal(xml, prefix) && !uri.Equals(XmlReservedNs.NsXml))) {
  142.                 throw new ArgumentException(Res.GetString(Res.Xml_XmlPrefix));
  143.             }
  144.             if (Ref.Equal(xmlNs, prefix)) {
  145.                 throw new ArgumentException(Res.GetString(Res.Xml_XmlnsPrefix));
  146.             }
  147.            
  148.             int declIndex = LookupNamespaceDecl(prefix);
  149.             int previousDeclIndex = -1;
  150.             if (declIndex != -1) {
  151.                 if (nsdecls[declIndex].scopeId == scopeId) {
  152.                     // redefine if in the same scope
  153.                     nsdecls[declIndex].uri = uri;
  154.                     return;
  155.                 }
  156.                 else {
  157.                     // othewise link
  158.                     previousDeclIndex = declIndex;
  159.                 }
  160.             }
  161.            
  162.             // set new namespace declaration
  163.             if (lastDecl == nsdecls.Length - 1) {
  164.                 NamespaceDeclaration[] newNsdecls = new NamespaceDeclaration[nsdecls.Length * 2];
  165.                 Array.Copy(nsdecls, 0, newNsdecls, 0, nsdecls.Length);
  166.                 nsdecls = newNsdecls;
  167.             }
  168.            
  169.             nsdecls[++lastDecl].Set(prefix, uri, scopeId, previousDeclIndex);
  170.            
  171.             // add to hashTable
  172.             if (useHashtable) {
  173.                 hashTable[prefix] = lastDecl;
  174.             }
  175.             // or create a new hashTable if the threashold has been reached
  176.             else if (lastDecl >= MinDeclsCountForHashtable) {
  177.                 // add all to hash table
  178.                 Debug.Assert(hashTable == null);
  179.                 hashTable = new Dictionary<string, int>(lastDecl);
  180.                 for (int i = 0; i <= lastDecl; i++) {
  181.                     hashTable[nsdecls[i].prefix] = i;
  182.                 }
  183.                 useHashtable = true;
  184.             }
  185.         }
  186.        
  187.         public virtual void RemoveNamespace(string prefix, string uri)
  188.         {
  189.             if (uri == null) {
  190.                 throw new ArgumentNullException("uri");
  191.             }
  192.             if (prefix == null) {
  193.                 throw new ArgumentNullException("prefix");
  194.             }
  195.            
  196.             int declIndex = LookupNamespaceDecl(prefix);
  197.             while (declIndex != -1) {
  198.                 if (String.Equals(nsdecls[declIndex].uri, uri) && nsdecls[declIndex].scopeId == scopeId) {
  199.                     nsdecls[declIndex].uri = null;
  200.                 }
  201.                 declIndex = nsdecls[declIndex].previousNsIndex;
  202.             }
  203.         }
  204.        
  205.         public virtual IEnumerator GetEnumerator()
  206.         {
  207.             Hashtable prefixes = new Hashtable(lastDecl + 1);
  208.             for (int thisDecl = 0; thisDecl <= lastDecl; thisDecl++) {
  209.                 if (nsdecls[thisDecl].uri != null) {
  210.                     prefixes[nsdecls[thisDecl].prefix] = nsdecls[thisDecl].prefix;
  211.                 }
  212.             }
  213.             return prefixes.Keys.GetEnumerator();
  214.         }
  215.        
  216.         #pragma warning disable 3002
  217.         public virtual IDictionary<string, string> GetNamespacesInScope(XmlNamespaceScope scope)
  218.         {
  219.             #pragma warning restore 3002
  220.             int i = 0;
  221.             switch (scope) {
  222.                 case XmlNamespaceScope.All:
  223.                     i = 2;
  224.                     break;
  225.                 case XmlNamespaceScope.ExcludeXml:
  226.                     i = 3;
  227.                     break;
  228.                 case XmlNamespaceScope.Local:
  229.                     i = lastDecl;
  230.                     while (nsdecls[i].scopeId == scopeId) {
  231.                         i--;
  232.                         Debug.Assert(i >= 2);
  233.                     }
  234.                     i++;
  235.                     break;
  236.             }
  237.            
  238.             Dictionary<string, string> dict = new Dictionary<string, string>(lastDecl - i + 1);
  239.             for (; i <= lastDecl; i++) {
  240.                 string prefix = nsdecls[i].prefix;
  241.                 string uri = nsdecls[i].uri;
  242.                 Debug.Assert(prefix != null);
  243.                
  244.                 if (uri != null) {
  245.                     if (uri.Length > 0 || prefix.Length > 0 || scope == XmlNamespaceScope.Local) {
  246.                         dict[prefix] = uri;
  247.                     }
  248.                     else {
  249.                         // default namespace redeclared to "" -> remove from list for all scopes other than local
  250.                         dict.Remove(prefix);
  251.                     }
  252.                 }
  253.             }
  254.             return dict;
  255.         }
  256.        
  257.         public virtual string LookupNamespace(string prefix)
  258.         {
  259.             int declIndex = LookupNamespaceDecl(prefix);
  260.             return (declIndex == -1) ? null : nsdecls[declIndex].uri;
  261.         }
  262.        
  263.         private int LookupNamespaceDecl(string prefix)
  264.         {
  265.             if (useHashtable) {
  266.                 int declIndex;
  267.                 if (hashTable.TryGetValue(prefix, out declIndex)) {
  268.                     while (declIndex != -1 && nsdecls[declIndex].uri == null) {
  269.                         declIndex = nsdecls[declIndex].previousNsIndex;
  270.                     }
  271.                     return declIndex;
  272.                 }
  273.                 return -1;
  274.             }
  275.             else {
  276.                 // First assume that prefix is atomized
  277.                 for (int thisDecl = lastDecl; thisDecl >= 0; thisDecl--) {
  278.                     if ((object)nsdecls[thisDecl].prefix == (object)prefix && nsdecls[thisDecl].uri != null) {
  279.                         return thisDecl;
  280.                     }
  281.                 }
  282.                
  283.                 // Non-atomized lookup
  284.                 for (int thisDecl = lastDecl; thisDecl >= 0; thisDecl--) {
  285.                     if (String.Equals(nsdecls[thisDecl].prefix, prefix) && nsdecls[thisDecl].uri != null) {
  286.                         return thisDecl;
  287.                     }
  288.                 }
  289.             }
  290.             return -1;
  291.         }
  292.        
  293.         public virtual string LookupPrefix(string uri)
  294.         {
  295.             // Don't assume that prefix is atomized
  296.             for (int thisDecl = lastDecl; thisDecl >= 0; thisDecl--) {
  297.                 if (String.Equals(nsdecls[thisDecl].uri, uri)) {
  298.                     string prefix = nsdecls[thisDecl].prefix;
  299.                     if (String.Equals(LookupNamespace(prefix), uri)) {
  300.                         return prefix;
  301.                     }
  302.                 }
  303.             }
  304.             return null;
  305.         }
  306.        
  307.         public virtual bool HasNamespace(string prefix)
  308.         {
  309.             // Don't assume that prefix is atomized
  310.             for (int thisDecl = lastDecl; nsdecls[thisDecl].scopeId == scopeId; thisDecl--) {
  311.                 if (String.Equals(nsdecls[thisDecl].prefix, prefix) && nsdecls[thisDecl].uri != null) {
  312.                     if (prefix.Length > 0 || nsdecls[thisDecl].uri.Length > 0) {
  313.                         return true;
  314.                     }
  315.                     return false;
  316.                 }
  317.             }
  318.             return false;
  319.         }
  320.        
  321.         internal bool GetNamespaceDeclaration(int idx, out string prefix, out string uri)
  322.         {
  323.             idx = lastDecl - idx;
  324.             if (idx < 0) {
  325.                 prefix = uri = null;
  326.                 return false;
  327.             }
  328.            
  329.             prefix = nsdecls[idx].prefix;
  330.             uri = nsdecls[idx].uri;
  331.            
  332.             return true;
  333.         }
  334.     }
  335.     //XmlNamespaceManager
  336. }

Developer Fusion