You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@xalan.apache.org by db...@locus.apache.org on 2000/06/29 22:28:36 UTC
cvs commit: xml-xalan/c/src/DOMSupport DOMServices.cpp NamespaceResolver.cpp
dbertoni 00/06/29 13:28:33
Modified: c/src/DOMSupport DOMServices.cpp NamespaceResolver.cpp
Log:
Fixes for attribute namespace problems -- courtesy of Joe Kesselman.
Revision Changes Path
1.12 +33 -6 xml-xalan/c/src/DOMSupport/DOMServices.cpp
Index: DOMServices.cpp
===================================================================
RCS file: /home/cvs/xml-xalan/c/src/DOMSupport/DOMServices.cpp,v
retrieving revision 1.11
retrieving revision 1.12
diff -u -r1.11 -r1.12
--- DOMServices.cpp 2000/06/01 16:23:41 1.11
+++ DOMServices.cpp 2000/06/29 20:28:23 1.12
@@ -265,7 +265,8 @@
}
-
+// Note: This may be inefficient in a Level 2 DOM, where localname
+// and prefix may (or may not) have been stored in separate fields
XalanDOMString
DOMServices::getLocalNameOfNode(const XalanNode& n)
{
@@ -382,8 +383,28 @@
return parent;
}
-
+// Note functional overlap with NamespaceResolver's
+// getNamespaceOfNode() method.
+//
+// ***** Also: although this may not yet impact Xalan,
+// as of DOM Level 2 it is possible for a hand-constructed DOM to
+// have namespaced nodes with no declaration in scope. In DOM2 it's
+// considered the responsibility of application code such as DOM
+// serializers to recognize these cases and synthesize appropriate
+// declarations when necessary. DOM3 is expected to add
+// some form of namespaceNormalize() operation to assist this task.
+//
+// DOM3 may also add a resolveNamespacePrefix() operation
+// which is aware of these issues and can generate reasonable
+// results even for a non-NS-normalized tree. The expected logic
+// is that a Namespaced node with a prefix will constitute an
+// implicit declaration of that prefix.
+//
+// If we cut over to DOM2 and want to accept DOMs from sources other
+// than the parser, we need to decide between demanding a
+// namespace-normalized DOM as input, doing a normalize pass
+// (full treewalk, expensive), or recognizing implicit declarations.
XalanDOMString
DOMServices::getNamespaceForPrefix(
const XalanDOMString& prefix,
@@ -391,6 +412,7 @@
{
XalanDOMString theNamespace;
+ // Reserved xml: is hardcoded
if(equals(prefix, s_XMLString) == true)
{
theNamespace = s_XMLNamespaceURI;
@@ -400,12 +422,17 @@
XalanNode::NodeType type;
const XalanNode* parent = &namespaceContext;
+ // Consider elements until NS is resolved, or we run out of
+ // ancestors, or we hit something other than an Element or
+ // EntityReference node (ie, Document or DocumentFragment)
while (parent != 0 && length(theNamespace) == 0
&& ((type = parent->getNodeType()) == XalanNode::ELEMENT_NODE
|| type == XalanNode::ENTITY_REFERENCE_NODE))
{
if (type == XalanNode::ELEMENT_NODE)
{
+ // Scan the attributes for xmlns:* or xmlns:
+ // (The latter is the prefix=="" case.)
const XalanNamedNodeMap* const nnm = parent->getAttributes();
assert(nnm != 0);
@@ -428,13 +455,13 @@
if (equals(aname, s_XMLNamespace) || isPrefix)
{
+ // slightly inefficient for default decl.
const unsigned int index = indexOf(aname,
':');
- const XalanDOMString p =
- isPrefix ? substring(aname,
- index + 1,
- len) : XalanDOMString();
+ const XalanDOMString p = (isPrefix)
+ ? substring(aname,index + 1,len)
+ : XalanDOMString();
if (equals(p, prefix) == true)
{
1.9 +77 -34 xml-xalan/c/src/DOMSupport/NamespaceResolver.cpp
Index: NamespaceResolver.cpp
===================================================================
RCS file: /home/cvs/xml-xalan/c/src/DOMSupport/NamespaceResolver.cpp,v
retrieving revision 1.8
retrieving revision 1.9
diff -u -r1.8 -r1.9
--- NamespaceResolver.cpp 2000/05/31 16:58:11 1.8
+++ NamespaceResolver.cpp 2000/06/29 20:28:24 1.9
@@ -91,7 +91,7 @@
}
-
+// Manefest constants: Prebuilt NSInfo objects for standard combinations
static NSInfo theNSInfoUnProcWithXMLNS(false, true);
static NSInfo theNSInfoUnProcWithoutXMLNS(false, false);
static NSInfo theNSInfoUnProcNoAncestorXMLNS(false, false, NSInfo::ANCESTORNOXMLNS);
@@ -99,8 +99,8 @@
static NSInfo theNSInfoNullWithoutXMLNS(true, false);
static NSInfo theNSInfoNullNoAncestorXMLNS(true, false, NSInfo::ANCESTORNOXMLNS);
-
+// Set (or reset) the cached NSInfo associated with a Node
void
NamespaceResolver::updateNamespace(
const XalanNode* theNode,
@@ -118,7 +118,12 @@
}
-
+// Find the name of the namespace bound to the current node. This is done by searching
+// upward through the model for a Namespace Declaration attribute. Once resolved, the
+// namespace is cached in the m_NSInfos table for faster retrieval.
+//
+// Note that DOM Level 2 binds this value at the time the node is built, which should
+// be considerably more efficient.
XalanDOMString
NamespaceResolver::getNamespaceOfNode(const XalanNode& theNode) const
{
@@ -175,33 +180,30 @@
XalanDOMString prefix;
- // If we have an attribute node without a prefix, then
- // we should use the prefix of the element parent.
- if(XalanNode::ATTRIBUTE_NODE == ntype)
+ // JKESS CHANGE: Attributes which have no prefix have no namespace,
+ // per standard Namespaces In XML behavior. They should not inherit from
+ // their owning Element, nor use the default namespace.
+ if(XalanNode::ATTRIBUTE_NODE == ntype && indexOfNSSep >= length(nodeName))
{
- if(indexOfNSSep < length(nodeName))
- {
- prefix = substring(nodeName, 0, indexOfNSSep);
- }
- else
- {
- theLocalNode = DOMServices::getParentOfNode(*theLocalNode);
-
- nodeName = theLocalNode->getNodeName();
-
- indexOfNSSep = indexOf(nodeName, ':');
+ // Attibute nodes aren't handled by the nsInfos logic above.
+ // And since this is the no-prefix case, it won't buy us anything for
+ // explicit prefix lookups. Hence, I don't see any reason to register
+ // this result via updateNamespace.
- prefix = indexOfNSSep < length(nodeName) ? substring(nodeName, 0, indexOfNSSep) : XalanDOMString();
- }
- }
- else
- {
- prefix = indexOfNSSep < length(nodeName) ? substring(nodeName, 0, indexOfNSSep) : XalanDOMString();
+ // BIG UGLY RETURN HERE!!!!!!!
+ return namespaceOfPrefix;
}
+ prefix = (indexOfNSSep < length(nodeName))
+ ? substring(nodeName, 0, indexOfNSSep)
+ : XalanDOMString();
+
bool ancestorsHaveXMLNS = false;
bool nHasXMLNS = false;
+ // The xml: prefix is hardcoded
+ // (In the DOM, so is the xmlns: prefix... but that's DOM behavior,
+ // not specified by the NS spec.)
if(equals(prefix, DOMServices::s_XMLString) == true)
{
namespaceOfPrefix = DOMServices::s_XMLNamespaceURI;
@@ -216,6 +218,7 @@
CandidateNoAncestorVectorType candidateNoAncestorXMLNS;
+ // Hunt upward until resolve namespace or fail to do so.
while (0 != parent && length(namespaceOfPrefix) == 0)
{
if(theIterator != m_NSInfos.end()
@@ -231,8 +234,10 @@
{
bool elementHasXMLNS = false;
+ // Elements
if (parentType == XalanNode::ELEMENT_NODE)
{
+ // Scan the Element's Attr's, looking for namespace declarations
const XalanNamedNodeMap* const nnm =
parent->getAttributes();
assert(nnm != 0);
@@ -245,23 +250,31 @@
const XalanDOMString aname = attr->getNodeName();
+ // Quick test of first character, to reduce cost of startsWith.
if(charAt(aname, 0) == 'x')
{
+ // "xmlns:"* prefix declaration?
bool isPrefix = startsWith(aname, DOMServices::s_XMLNamespaceWithSeparator);
- if (equals(aname, DOMServices::s_XMLNamespace) == true || isPrefix == true)
+ // or "xmlns" default declaration?
+ // JKESS: Reversed order of test; more efficient.
+ if (isPrefix == true || equals(aname, DOMServices::s_XMLNamespace) == true)
{
+ // Is this element the original node?
if(theLocalNode == parent)
{
- nHasXMLNS = true;
+ nHasXMLNS = true; // local decls exist
}
- elementHasXMLNS = true;
- ancestorsHaveXMLNS = true;
+ elementHasXMLNS = true; // decls exist on current parent
+ ancestorsHaveXMLNS = true; // decls exist somewhere
- const XalanDOMString p = isPrefix == true ?
- substring(aname, length(DOMServices::s_XMLNamespaceWithSeparator)) : XalanDOMString();
+ // If xmlns:, what prefix is declared?
+ const XalanDOMString p = (isPrefix == true)
+ ? substring(aname, length(DOMServices::s_XMLNamespaceWithSeparator))
+ : XalanDOMString();
+ // If it's the one we're looking for, resolve to NS
if (equals(p, prefix) == true)
{
namespaceOfPrefix = attr->getNodeValue();
@@ -272,21 +285,31 @@
}
}
+ // Fallthough for unresolved Elements,
+ // plus anything else except Attr's
if((XalanNode::ATTRIBUTE_NODE != parentType) &&
(theIterator == m_NSInfos.end()) &&
(theLocalNode != parent))
{
- nsInfo = elementHasXMLNS ? theNSInfoUnProcWithXMLNS :
- theNSInfoUnProcWithoutXMLNS;
-
+ // Record whether this node defines any namespaces
+ // (_not_ whether it defines its own or what that is)
+ nsInfo = elementHasXMLNS
+ ? theNSInfoUnProcWithXMLNS
+ : theNSInfoUnProcWithoutXMLNS;
updateNamespace(parent, nsInfo);
}
}
+ // Attr nodes need to look to their owning Element for their NS
+ // declaration (if any). Note that we're using the XPath data model,
+ // getParentOfNode(); in DOM terms, that's Attr.getOwningElement().
if(XalanNode::ATTRIBUTE_NODE == parentType)
{
parent = DOMServices::getParentOfNode(*parent);
}
+
+ // Any other node gets queued for annotation pass,
+ // along with our current nsInfo context
else
{
candidateNoAncestorXMLNS.push_back(make_pair(parent, nsInfo));
@@ -294,8 +317,12 @@
parent = parent->getParentNode();
}
+ // If we haven't run out of ancestors
if(0 != parent)
{
+ // Try to retrieve cached NS info for the newly selected parent
+ // for use in next pass through loop.
+ // If not found, continue using previous value
theIterator = m_NSInfos.find(parent);
if (theIterator != m_NSInfos.end())
@@ -305,10 +332,15 @@
}
}
+ // Anotation pass over the "any other node" queue
const int nCandidates = candidateNoAncestorXMLNS.size();
if(nCandidates > 0)
{
+ // If no inherited declarations (and we checked all the way to the root)
+ // then record nodes with no local declarations in the nsInfo cache,
+ // to avoid repeatedly searching this branch of the tree.
+ // ????? This feels overcomplicated, somehow...
if(false == ancestorsHaveXMLNS && 0 == parent)
{
for(int i = 0; i < nCandidates; i++)
@@ -327,29 +359,40 @@
}
}
+ // NOTE that attibute nodes aren't handled by the nsInfos logic,
+ // so it's unclear that the updateNamespace buys us anything directly.
+ // But I'm guessing it may be useful for getNamespaceForPrefix.
+ //
+ // ????? This seems like a lot of code for something which should be a set of
+ // bit-masks...
if(XalanNode::ATTRIBUTE_NODE != ntype)
{
+ // If Attribute's prefix wasn't resolved
if(0 == length(namespaceOfPrefix))
{
+ // In context where other prefixes are defined
if(ancestorsHaveXMLNS == true)
{
+ // Local definitions exist
if(nHasXMLNS == true)
{
updateNamespace(theLocalNode, theNSInfoNullWithXMLNS);
}
+ // Only inherited definitions exist
else
{
updateNamespace(theLocalNode, theNSInfoNullWithoutXMLNS);
}
}
- else
+ // No definitions exist
+ else
{
updateNamespace(theLocalNode, theNSInfoNullNoAncestorXMLNS);
}
}
- else
+ else // Attribute's prefix was resolved, at least that one is declared
{
updateNamespace(theLocalNode, NSInfo(namespaceOfPrefix, nHasXMLNS));
}