##// END OF EJS Templates
sync
sync

File last commit:

r289:95896f882995 v3.0.14 v3
r291:450a55e0c222 v3
Show More
XmlNameContext.cs
119 lines | 4.3 KiB | text/x-csharp | CSharpLexer
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));
}
}
}
}