forked from mirrors/gecko-dev
Serialize an xmlns="" as needed if nodes are in the null namespace but their
ancestors have a default namespace. Bug 301260, r+sr=peterv
This commit is contained in:
parent
537e3c4829
commit
14107143f5
2 changed files with 64 additions and 31 deletions
|
|
@ -335,33 +335,60 @@ PRBool
|
|||
nsXMLContentSerializer::ConfirmPrefix(nsAString& aPrefix,
|
||||
const nsAString& aURI,
|
||||
nsIDOMElement* aElement,
|
||||
PRBool aMustHavePrefix)
|
||||
PRBool aIsAttribute)
|
||||
{
|
||||
if (aPrefix.EqualsLiteral(kXMLNS) ||
|
||||
(aPrefix.EqualsLiteral("xml") &&
|
||||
aURI.EqualsLiteral("http://www.w3.org/XML/1998/namespace"))) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
if (aURI.IsEmpty()) {
|
||||
aPrefix.Truncate();
|
||||
return PR_FALSE;
|
||||
|
||||
PRBool mustHavePrefix;
|
||||
if (aIsAttribute) {
|
||||
if (aURI.IsEmpty()) {
|
||||
// Attribute in the null namespace. This just shouldn't have a prefix.
|
||||
// And there's no need to push any namespace decls
|
||||
aPrefix.Truncate();
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
// Attribute not in the null namespace -- must have a prefix
|
||||
mustHavePrefix = PR_TRUE;
|
||||
} else {
|
||||
// Not an attribute, so doesn't _have_ to have a prefix
|
||||
mustHavePrefix = PR_FALSE;
|
||||
}
|
||||
|
||||
// Keep track of the closest prefix that's bound to aURI and whether we've
|
||||
// found such a thing. closestURIMatch holds the prefix, and uriMatch
|
||||
// indicates whether we actually have one.
|
||||
nsAutoString closestURIMatch;
|
||||
PRBool uriMatch = PR_FALSE;
|
||||
|
||||
// Also keep track of whether we've seen aPrefix already. If we have, that
|
||||
// means that it's already bound to a URI different from aURI, so even if we
|
||||
// later (so in a more outer scope) see it bound to aURI we can't reuse it.
|
||||
PRBool haveSeenOurPrefix = PR_FALSE;
|
||||
|
||||
PRInt32 count = mNameSpaceStack.Count();
|
||||
PRInt32 index = count - 1;
|
||||
while (index >= 0) {
|
||||
NameSpaceDecl* decl = (NameSpaceDecl*)mNameSpaceStack.ElementAt(index);
|
||||
// Check if we've found a prefix match
|
||||
if (aPrefix.Equals(decl->mPrefix)) {
|
||||
|
||||
// If the URI's match, we don't have to add a namespace decl
|
||||
if (aURI.Equals(decl->mURI)) {
|
||||
return PR_FALSE;
|
||||
|
||||
// If the URIs match and aPrefix is not bound to any other URI, we can
|
||||
// use aPrefix
|
||||
if (!haveSeenOurPrefix && aURI.Equals(decl->mURI)) {
|
||||
// Just use our uriMatch stuff. That will deal with an empty aPrefix
|
||||
// the right way. We can break out of the loop now, though.
|
||||
uriMatch = PR_TRUE;
|
||||
closestURIMatch = aPrefix;
|
||||
break;
|
||||
}
|
||||
|
||||
haveSeenOurPrefix = PR_TRUE;
|
||||
|
||||
// If they don't, and either:
|
||||
// 1) We have a prefix (so we'd be redeclaring this prefix to point to a
|
||||
// different namespace) or
|
||||
|
|
@ -372,14 +399,14 @@ nsXMLContentSerializer::ConfirmPrefix(nsAString& aPrefix,
|
|||
// URIs when |decl| doesn't have aElement as its owner. In that case we
|
||||
// can simply push the new namespace URI as the default namespace for
|
||||
// aElement.
|
||||
if (!aPrefix.IsEmpty() ||
|
||||
(decl->mPrefix.IsEmpty() && decl->mOwner == aElement)) {
|
||||
if (!aPrefix.IsEmpty() || decl->mOwner == aElement) {
|
||||
GenerateNewPrefix(aPrefix);
|
||||
// Now we need to validate our new prefix/uri combination; check it
|
||||
// against the full namespace stack again. Note that just restarting
|
||||
// the while loop is ok, since we haven't changed aURI, so the
|
||||
// closestURIMatch state is not affected.
|
||||
// closestURIMatch and uriMatch state is not affected.
|
||||
index = count - 1;
|
||||
haveSeenOurPrefix = PR_FALSE;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
|
@ -406,33 +433,41 @@ nsXMLContentSerializer::ConfirmPrefix(nsAString& aPrefix,
|
|||
}
|
||||
|
||||
// At this point the following invariants hold:
|
||||
// 1) There is nothing on the namespace stack that matches the pair
|
||||
// (aPrefix, aURI)
|
||||
// 1) The prefix in closestURIMatch is mapped to aURI in our scope if
|
||||
// uriMatch is set.
|
||||
// 2) There is nothing on the namespace stack that has aPrefix as the prefix
|
||||
// and a _different_ URI, except for the case aPrefix.IsEmpty (and
|
||||
// possible default namespaces on ancestors)
|
||||
// 3) The prefix in closestURIMatch is mapped to aURI in our scope if
|
||||
// uriMatch is set.
|
||||
|
||||
// So if uriMatch is set it's OK to use the closestURIMatch prefix. The one
|
||||
// exception is when closestURIMatch is actually empty (default namespace
|
||||
// decl) and we must have a prefix.
|
||||
if (uriMatch && (!aMustHavePrefix || !closestURIMatch.IsEmpty())) {
|
||||
if (uriMatch && (!mustHavePrefix || !closestURIMatch.IsEmpty())) {
|
||||
aPrefix.Assign(closestURIMatch);
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
// At this point, if aPrefix is empty (which means we never had a prefix to
|
||||
// start with) and we must have a prefix, just generate a new prefix and then
|
||||
// send it back through the namespace stack checks to make sure it's OK.
|
||||
if (aPrefix.IsEmpty() && aMustHavePrefix) {
|
||||
GenerateNewPrefix(aPrefix);
|
||||
return ConfirmPrefix(aPrefix, aURI, aElement, aMustHavePrefix);
|
||||
}
|
||||
// else we will just set aURI as the new default namespace URI
|
||||
if (aPrefix.IsEmpty()) {
|
||||
// At this point, aPrefix is empty (which means we never had a prefix to
|
||||
// start with). If we must have a prefix, just generate a new prefix and
|
||||
// then send it back through the namespace stack checks to make sure it's
|
||||
// OK.
|
||||
if (mustHavePrefix) {
|
||||
GenerateNewPrefix(aPrefix);
|
||||
return ConfirmPrefix(aPrefix, aURI, aElement, aIsAttribute);
|
||||
}
|
||||
|
||||
// Indicate that we need to create a namespace decl for the
|
||||
// final prefix
|
||||
// One final special case. If aPrefix is empty and we never saw an empty
|
||||
// prefix (default namespace decl) on the namespace stack and we're in the
|
||||
// null namespace there is no reason to output an |xmlns=""| here. It just
|
||||
// makes the output less readable.
|
||||
if (!haveSeenOurPrefix && aURI.IsEmpty()) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
// Now just set aURI as the new default namespace URI. Indicate that we need
|
||||
// to create a namespace decl for the final prefix
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
|
|
@ -626,8 +661,7 @@ nsXMLContentSerializer::AppendElementStart(nsIDOMElement *aElement,
|
|||
addNSAttr = PR_FALSE;
|
||||
if (kNameSpaceID_XMLNS != namespaceID) {
|
||||
nsContentUtils::NameSpaceManager()->GetNameSpaceURI(namespaceID, uriStr);
|
||||
addNSAttr = ConfirmPrefix(prefixStr, uriStr, aElement,
|
||||
namespaceID != kNameSpaceID_None);
|
||||
addNSAttr = ConfirmPrefix(prefixStr, uriStr, aElement, PR_TRUE);
|
||||
}
|
||||
|
||||
content->GetAttr(namespaceID, attrName, valueStr);
|
||||
|
|
|
|||
|
|
@ -118,8 +118,7 @@ class nsXMLContentSerializer : public nsIContentSerializer {
|
|||
* @param aURI the namespace URI we want aPrefix to point to
|
||||
* @param aElement the element we're working with (needed for proper default
|
||||
* namespace handling)
|
||||
* @param aMustHavePrefix PR_TRUE if we the output prefix must be nonempty
|
||||
* whenever a new namespace decl is needed.
|
||||
* @param aIsAttribute PR_TRUE if we're confirming a prefix for an attribute.
|
||||
* @return PR_TRUE if we need to push the (prefix, uri) pair on the namespace
|
||||
* stack (note that this can happen even if the prefix is
|
||||
* empty).
|
||||
|
|
@ -127,7 +126,7 @@ class nsXMLContentSerializer : public nsIContentSerializer {
|
|||
PRBool ConfirmPrefix(nsAString& aPrefix,
|
||||
const nsAString& aURI,
|
||||
nsIDOMElement* aElement,
|
||||
PRBool aMustHavePrefix);
|
||||
PRBool aIsAttribute);
|
||||
/**
|
||||
* GenerateNewPrefix generates a new prefix and writes it to aPrefix
|
||||
*/
|
||||
|
|
|
|||
Loading…
Reference in a new issue