Mercurial > pub > ImplabNet
view Implab/Xml/XmlNameContext.cs @ 229:5f7a3e1d32b9 v2
JsonXmlReader performance tuning
JsonScanner now operates strings and doesn't
parses number and literals.
Added SerializationHelpers to common serialize/deserialize operations
author | cin |
---|---|
date | Tue, 12 Sep 2017 19:07:42 +0300 |
parents | 8d5de4eb9c2c |
children |
line wrap: on
line source
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Xml; namespace Implab.Xml { class XmlNameContext { public const string XmlnsNamespace = "http://www.w3.org/2000/xmlns/"; public const string XmlnsPrefix = "xmlns"; public const string XmlNamespace = "http://www.w3.org/XML/1998/namespace"; public const string XmlPrefix = "xml"; public const string XsiNamespace = "http://www.w3.org/2001/XMLSchema-instance"; public const string XsiPrefix = "xsi"; readonly static char[] _qNameDelim = new[] { ':' }; Dictionary<string, string> m_ns2prefix; Dictionary<string, string> m_prefix2ns; int m_nextPrefix = 1; string m_lastNs; string m_lastPrefix; public XmlNameContext ParentContext { get; private set; } public int Depth { get; private set; } public XmlNameContext(XmlNameContext parent, int depth) { ParentContext = parent; Depth = depth; if (parent == null) { DefinePrefixNoCheck(XmlnsNamespace, XmlnsPrefix); DefinePrefixNoCheck(XmlNamespace, XmlPrefix); } else { m_nextPrefix = parent.m_nextPrefix; } } public bool LookupNamespacePrefix(string ns, out string prefix) { if (ns == null) ns = string.Empty; if (ns == m_lastNs) { prefix = m_lastPrefix; return true; } prefix = null; for (var ctx = this; ctx != null; ctx = ctx.ParentContext) { if (ctx.m_ns2prefix != null && ctx.m_ns2prefix.TryGetValue(ns, out prefix)) { m_lastNs = ns; m_lastPrefix = prefix; return true; } } return false; } public string CreateNamespacePrefix(string ns) { var prefix = $"p{m_nextPrefix++}"; DefinePrefixNoCheck(ns, prefix); return prefix; } void DefinePrefixNoCheck(string ns, string prefix) { if (ns == null) ns = string.Empty; if (prefix == null) prefix = string.Empty; if (m_ns2prefix == null) m_ns2prefix = new Dictionary<string, string>(); m_ns2prefix[ns] = prefix; if (m_prefix2ns == null) m_prefix2ns = new Dictionary<string, string>(); m_prefix2ns[prefix] = ns; } public void DefinePrefix(string ns, string prefix) { // according to https://www.w3.org/TR/xml-names/#ns-decl // It MUST NOT be declared . Other prefixes MUST NOT be bound to this namespace name, and it MUST NOT be declared as the default namespace if (ns == XmlnsNamespace) throw new Exception($"Attempt to define xmlns:{prefix}='{ns}'"); // It MAY, but need not, be declared, and MUST NOT be bound to any other namespace name if (ns == XmlNamespace && prefix != XmlPrefix) throw new Exception($"Attempt to define xmlns:{prefix}='{ns}'"); // add mapping DefinePrefixNoCheck(ns, prefix); } public string ResolvePrefix(string prefix) { if (prefix == null) prefix = string.Empty; string ns = null; for(var ctx = this; ctx != null; ctx = ctx.ParentContext) { if (ctx.m_prefix2ns != null && ctx.m_prefix2ns.TryGetValue(prefix, out ns) == true) return ns; } return null; } public XmlQualifiedName Resolve(string name) { Safe.ArgumentNotEmpty(name, nameof(name)); var parts = name.Split(_qNameDelim, 2, StringSplitOptions.RemoveEmptyEntries); if (parts.Length == 2) { return new XmlQualifiedName(parts[1], ResolvePrefix(parts[0])); } else { return new XmlQualifiedName(parts[0], ResolvePrefix(string.Empty)); } } } }