Bug 22958

Summary: Attribute namespaces are serialized as if they were element ones
Product: WebKit Reporter: Alexey Proskuryakov <ap>
Component: DOMAssignee: Nobody <webkit-unassigned>
Status: RESOLVED FIXED    
Severity: Normal CC: alex, cdumez, emacemac7, jchaffraix, peter.rietzler, rwlbuis, webkitbooger
Priority: P2    
Version: 528+ (Nightly build)   
Hardware: All   
OS: All   
Attachments:
Description Flags
test case
none
A example that demonstrates the different possible ways to cause and/or fix the problem. none

Description Alexey Proskuryakov 2008-12-22 01:10:55 PST
If an attribute is created with setAttributeNS(), its namespace is printed as if it were a default one.

On the attached test, two default namespaces are printed.
Comment 1 Alexey Proskuryakov 2008-12-22 01:11:17 PST
Created attachment 26197 [details]
test case
Comment 2 Alexey Proskuryakov 2011-04-11 11:12:17 PDT
*** Bug 58221 has been marked as a duplicate of this bug. ***
Comment 3 Leo B 2013-04-04 02:09:35 PDT
Still seeing essentially same problem in Google Chrome Version 26.0.1410.43 m.

As verified in the developer tools debugger, in scope variables, setAttributeNS does this:

For the element creates an attribute, but the attribute's namespaceURI is null.

And for the element it creates a second attribute that hasn't been asked for, of name xmlns with value being what should have been the namespaceURI of the attribute that has been asked for.

The solution / workaround is:  Pass in a qualified name and it will work!  For most compatibility, you probably should get the prefix with yourElement.lookupPrefix(yourNamespaceURI).

Workaround found by paying attention to http://www.w3.org/TR/DOM-Level-2-Core/core.html#ID-ElSetAttrNS where it says the second parameter is the qualifiedName, the qualified name of the attribute to create or alter.

Problem found when running new tests in http://srguiwiz.github.com/adj-js/user-docs/tests.html and it failed in Chrome as a consequence of setAttributeNS behavior.  It had passed in Firefox.  Since then fixed http://srguiwiz.github.com/adj-js/user-docs/ to use qualified name, now it works in Chrome as well.

Does this workaround and the specification mean this isn't a bug any more?
Comment 4 Alex Milowski 2013-06-15 14:48:06 PDT
(In reply to comment #3)

> 
> Does this workaround and the specification mean this isn't a bug any more?

This is still a bug.  The DOM API allows for the case where the prefix is not specified.  In such cases, the serializer needs to generate a prefix.

In my testing, the serializer clearly assumes the prefix property will be present.  The extra default namespace comes from the attempt to declare the prefix used for the namespace attribute.  When the prefix is not specified and there needs to be a prefix, the wrong thing happens.

I have a simple example the demonstrates the problem that I will attach.
Comment 5 Alex Milowski 2013-06-15 14:51:46 PDT
Created attachment 204774 [details]
A example that demonstrates the different possible ways to cause and/or fix the problem.

Note: In Firefox, you aren't allowed to set the prefix.  This is clearly a DOM bug for them as [1] says you are allowed to set the prefix. 

[1] http://www.w3.org/TR/DOM-Level-3-Core/core.html#ID-NodeNSPrefix
Comment 6 Alex Milowski 2013-06-18 16:22:54 PDT
Looking at the source, the problem is two fold:

  1. A prefix is not generated for the qualified name when it is missing.

  2. The attribute prefix, when set, is not passed properly to appendNamespace().


For (1), at MarkupAccumulator.cpp:455:
 
       QualifiedName prefixedName = attribute.name();
        if (attribute.namespaceURI() == XLinkNames::xlinkNamespaceURI) {
            if (!attribute.prefix())
                prefixedName.setPrefix(xlinkAtom);
        } else if (attribute.namespaceURI() == XMLNames::xmlNamespaceURI) {
            if (!attribute.prefix())
                prefixedName.setPrefix(xmlAtom);
        } else if (attribute.namespaceURI() == XMLNSNames::xmlnsNamespaceURI) {
            if (attribute.name() != XMLNSNames::xmlnsAttr && !attribute.prefix())
                prefixedName.setPrefix(xmlnsAtom);
        }
        result.append(prefixedName.toString());

There are an infinite number of cases that need to be handled here by a check for:

   } else if (attribute.namespaceURI() && !attribute.prefix()) {
       // generate a prefix ...
   }

and that is missing.

For (2), the actually prefix used (either what was set or what was given) needs to be tracked and passed later on to appendNamespace() instead of attribute.prefix() as that field may remain null in the case of generated or set prefixes.

Because you have to generate namespaces, it is unclear to me as of yet whether the current method of tracking in-scope namespaces will work properly.
Comment 7 Alex Milowski 2013-06-18 17:11:12 PDT
Bug 117764 is related to this problem.
Comment 8 Rob Buis 2013-08-29 06:46:49 PDT
Committed r154779: <http://trac.webkit.org/changeset/154779>
Comment 9 Lucas Forschler 2019-02-06 09:03:45 PST
Mass moving XML DOM bugs to the "DOM" Component.