PhoenixmlDb.XSLT
QNameNamespaces
The one place that answers "what namespace URI does this actually carry", and matches two QNames by URI rather than by interned id.
#QNameNamespaces
Namespace: PhoenixmlDb.Xslt
The one place that answers "what namespace URI does this
actually carry", and matches two QNames by URI rather than by interned id.
QName equality compares Namespace, an interned NamespaceId, not the URI string:
public bool Equals(QName other) => Namespace == other.Namespace && LocalName == other.LocalName;
That is correct and fast for QNames the parser interned from one stylesheet, because equal URIs get equal ids. It is wrong for a QName built at runtime by fn:QName(), which mints a hash-based id that never equals the parser's id for the same URI. Any dictionary keyed by QName then misses, even though the two names denote the same thing.
Which property holds the URI depends on how the QName was made: fn:QName(uri, local) populates RuntimeNamespace, so ResolvedNamespace is the one to read and ExpandedNamespace comes back empty; a parsed QName is the other way round. Reading only one silently matched nothing.
This has now cost three separate bugs — a vendor-options package that looked absent, an initial-template lookup, and fn:transform failing to find a namespaced entry point across sixteen XSpec suites. It lives here so there is no fourth.
#Methods
#Canonicalize(PhoenixmlDb.Core.QName)
Rewrites a QName built at RUNTIME — by
fn:QName()
, or parsed from an EQName — onto the interned id the parser would have given it, leaving a QName that compares equal to the parser's own.
Every name in an fn:transform option map arrives this way: the initial template, the initial mode, and every key of stylesheet-params, template-params and tunnel-params. Left uncanonicalized, a namespaced one carries a hash-based id, or worse NamespaceId.None, and then matches either NOTHING or the WRONG declaration — a namespaced initial mode collapsed to no namespace will happily select a same-local-name mode in no namespace and run it.
The URI strings are carried through unchanged: they are not part of QName identity, but namespace-uri-from-QName() and error messages still read them.
#InternedIdFor(String)
The interned
the stylesheet parser uses for a namespace URI.
is a process-wide intern table, and it is the one the parser itself goes through when it builds the QName of a declaration. Resolving a runtime URI through the SAME table therefore yields the SAME id, which is what makes ordinary QName equality work again — this repairs the identity rather than routing around it the way
does.
#SameExpandedName(PhoenixmlDb.Core.QName,PhoenixmlDb.Core.QName,Func<PhoenixmlDb.Core.QName,String>)
True when two QNames denote the same expanded name, comparing namespace URIs rather than interned ids. Use this to rescue a lookup that failed on id equality, not to replace it: the id comparison is the fast path and is right for names from a single parse.
#UriOf(PhoenixmlDb.Core.QName,Func<PhoenixmlDb.Core.QName,String>)
The namespace URI a QName carries, or the empty string for no namespace.
Three sources, because three kinds of QName reach here. A runtime
fn:QName()
fills
ResolvedNamespace
; a QName carrying its expanded form fills
ExpandedNamespace
; and a QName the parser built carries NEITHER string - it holds only the interned
NamespaceId
, so the URI has to be looked back up in the registry. Missing that last case is what made the first version of this helper still fail to match: both sides reported an empty URI and compared equal to nothing.