Mercurial > pub > ImplabNet
view Implab/Xml/XmlNameContext.cs @ 227:8d5de4eb9c2c v2
Reimplemented JsonXmlReader, added support for null values: JSON null values are
mapped to empty nodes with 'xsi:nil' attribute set to 'true'
author | cin |
---|---|
date | Sat, 09 Sep 2017 03:53:13 +0300 |
parents | |
children | 5f7a3e1d32b9 |
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 { public 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; public XmlNameContext ParentContext { get; private set; } public XmlNameContext(XmlNameContext parent) { ParentContext = parent; 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; prefix = null; for (var ctx = this; ctx != null; ctx = ctx.ParentContext) { if (ctx.m_ns2prefix?.TryGetValue(ns, out prefix) == true) { if (ctx != this) // cache for the future use DefinePrefixNoCheck(ns, 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?.TryGetValue(prefix, out ns) == true) { if (ctx != this) // cache for the future use DefinePrefixNoCheck(ns, prefix); 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)); } } } }