2007-04-21 Lamar Goddard <lamargoddard@gmail.com>
authorap <ap@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 21 Apr 2007 09:38:59 +0000 (09:38 +0000)
committerap <ap@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 21 Apr 2007 09:38:59 +0000 (09:38 +0000)
        Reviewed by Darin.

        Fix for http://bugs.webkit.org/show_bug.cgi?id=5262
        <rdar://problem/5018778>
        XMLSerializer drops Namespace information

WebCore:
        Updated WebCore::markup to output namespace information for elements/attributes whose namespace information
        doesn't appear in its scope in the output.

        * WebCore/editing/markup.cpp:
        (WebCore::createMarkup(const Node*, ...)): Changed call to WebCore::markup to match parameters
        (WebCore::markup): Changed recursive call to match tree structure, removed ASSERT and no longer needed includeSiblings parameter.
        (WebCore::startMarkup): Added optional parameter to track namespaces in the current scope.
        (WebCore::addNamespace): Function to add namespace information to markup.
        (WebCore::shouldAddNamespaceAttr):
        (WebCore::shouldAddNamespaceElem): Functions that test whether namespace information should be added for a given node.
        * WebCore/dom/Document.idl:
        (createElementNS):
        (createAttributeNS):
        (getElementsByTagNameNS): Added [ConvertNullToNullString] to namespaceURI parameter.
        * WebCore/dom/Node.cpp:
        (Node::getElementsByTagNameNS): removed test for namespaceURI being null as null can be a valid namespace.

LayoutTests:
        * fast/dom/serialize-nodes-expected.txt: Added.
        * fast/dom/serialize-nodes.xhtml: Added.
        * dom/xhtml/level3/core/nodeisequalnode14-expected.txt: This test fails because
        createAttribute is supposed to create an Attr with localName of null.
        * dom/xhtml/level3/core/nodeisequalnode15-expected.txt: Now succeeds.
        * fast/innerHTML/004-expected.txt: Added namespace information to head and body nodes
        as xhtml nodes now serialize with namespace information.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@20997 268f45cc-cd09-0410-ab3c-d52691b4dbfc

LayoutTests/ChangeLog
LayoutTests/dom/xhtml/level3/core/nodeisequalnode14-expected.txt
LayoutTests/dom/xhtml/level3/core/nodeisequalnode15-expected.txt
LayoutTests/fast/dom/serialize-nodes-expected.txt [new file with mode: 0644]
LayoutTests/fast/dom/serialize-nodes.xhtml [new file with mode: 0644]
LayoutTests/fast/innerHTML/004-expected.txt
WebCore/ChangeLog
WebCore/dom/Document.idl
WebCore/dom/Node.cpp
WebCore/editing/markup.cpp

index 4cea2457abbd908f5598d511dcfa1660588189c9..04cccecf389fa9cdc34ead72056503216196c2af 100644 (file)
@@ -1,3 +1,19 @@
+2007-04-21  Lamar Goddard  <lamargoddard@gmail.com>
+
+        Reviewed by Darin.
+
+        http://bugs.webkit.org/show_bug.cgi?id=5262
+        <rdar://problem/5018778>
+        XMLSerializer drops Namespace information
+
+        * fast/dom/serialize-nodes-expected.txt: Added.
+        * fast/dom/serialize-nodes.xhtml: Added.
+        * dom/xhtml/level3/core/nodeisequalnode14-expected.txt: This test fails because 
+        createAttribute is supposed to create an Attr with localName of null.
+        * dom/xhtml/level3/core/nodeisequalnode15-expected.txt: Now succeeds.
+        * fast/innerHTML/004-expected.txt: Added namespace information to head and body nodes
+        as xhtml nodes now serialize with namespace information.
+
 2007-04-21  Alexey Proskuryakov  <ap@webkit.org>
 
         Reviewed by Darin.
index 51995e139675ebfd413eb7fa893247dd18e3ddc7..9c54e441f9bcaf9fdfe263f9f9389dd105f5356d 100644 (file)
@@ -1,2 +1,3 @@
 Test   http://www.w3.org/2001/DOM-Test-Suite/level3/core/nodeisequalnode14
-Status Success
+Status failure
+Message        nodeisequalnode14: assertTrue failed
index f22a35fceba859a1741a93ce82b5ee11a0c7fa78..0d9d3eba8feaf0e7b2f577601d77c994b9770c9b 100644 (file)
@@ -1,3 +1,2 @@
 Test   http://www.w3.org/2001/DOM-Test-Suite/level3/core/nodeisequalnode15
-Status failure
-Message        nodeisequalnode15: assertTrue failed
+Status Success
diff --git a/LayoutTests/fast/dom/serialize-nodes-expected.txt b/LayoutTests/fast/dom/serialize-nodes-expected.txt
new file mode 100644 (file)
index 0000000..4357c35
--- /dev/null
@@ -0,0 +1,19 @@
+ALERT: foo:name is one and should be one
+ALERT: bar:name is two and should be two
+ALERT: name is three and should be three
+ALERT: node is child and should be child
+ALERT: <foo:root xmlns:foo="urn:foo-ns" foo:type="test"><child foo:name="one" bar:name="two" xmlns:bar="urn:bar-ns" name="three"/></foo:root>
+<div xmlns="http://www.w3.org/1999/xhtml" id="input">
+    <div>
+        <foo:node xmlns:foo="http://foo.com" xmlns="http://baz.com" foo:name="foo_name" bar:name="bar_name" xmlns:bar="http://bar.com">
+            <node foo:name="foo_name">
+                <bar:node xmlns:bar="http://bar2.com"/>
+            </node>
+        </foo:node>
+    </div>
+    <bar:node xmlns:bar="http://bar.com">
+        <br />
+    </bar:node>
+</div>
+
+
diff --git a/LayoutTests/fast/dom/serialize-nodes.xhtml b/LayoutTests/fast/dom/serialize-nodes.xhtml
new file mode 100644 (file)
index 0000000..8744065
--- /dev/null
@@ -0,0 +1,58 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:foo="http://foo.com" xmlns:bar="http://bar.com" version="-//W3C//DTD XHTML 1.1//EN" xml:lang="en">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
+<title>XMLSerializer() namespace test</title>
+<script>
+window.addEventListener("load", function() {
+    if (window.layoutTestController)
+        layoutTestController.dumpAsText();
+    
+    var xs = new XMLSerializer();
+    var content = document.getElementById('content');
+    content.firstChild.nodeValue = xs.serializeToString(document.getElementById('input'));
+
+    // Original test
+    var d = document.implementation.createDocument("urn:foo-ns", "foo:root", null);
+    if (!d.documentElement) {
+        // This shouldn't happen, since DomImplementation.createDocument
+        // is supposed to create the root element.  But in Safari, it's required.
+        d.appendChild(d.createElementNS("urn:foo-ns", "foo:root"));
+    }
+    var root = d.documentElement;
+    root.setAttributeNS("urn:foo-ns", "foo:type", "test")
+    
+    var c = d.createElementNS(null, "child");
+    root.appendChild(c);
+    
+    c.setAttributeNS("urn:foo-ns", "foo:name", "one");
+    c.setAttributeNS("urn:bar-ns", "bar:name", "two");
+    var attr = d.createAttributeNS(null, "name");
+    var text = d.createTextNode("three");
+    attr.appendChild(text);
+    c.setAttributeNode(attr);
+    
+    window.alert("foo:name is " + c.getAttributeNS("urn:foo-ns", "name") + " and should be one");
+    window.alert("bar:name is " + c.getAttributeNS("urn:bar-ns", "name") + " and should be two");
+    window.alert("name is " + c.getAttributeNS(null, "name") + " and should be three");
+    window.alert("node is " + d.getElementsByTagNameNS(null, "child").item(0).nodeName + " and should be child");
+    window.alert(xs.serializeToString(d));
+}, false);
+</script>
+</head>
+<body>
+<pre id="content">foo</pre>
+<div id="input">
+    <div>
+        <foo:node xmlns="http://baz.com" foo:name="foo_name" bar:name="bar_name">
+            <node foo:name="foo_name">
+                <bar:node xmlns:bar="http://bar2.com"/>
+            </node>
+        </foo:node>
+    </div>
+    <bar:node>
+        <br />
+    </bar:node>
+</div>
+</body>
+</html>
index 612f26ed528f44de40984f2e8e284ceb13dd5da7..df37b9dcd5fc1d23b5a16da7a704a9ca85928c7e 100644 (file)
@@ -1,10 +1,10 @@
 Content:
 
-<head>
+<head xmlns="http://www.w3.org/1999/xhtml">
 <meta name="description" content="This tests singular elements too" />
 <title>xhtml innerHTML test</title>
 </head>
-<body>
+<body xmlns="http://www.w3.org/1999/xhtml">
 <span>Content:</span>
 <pre id="content">placeholder</pre>
 <div></div>
index 6a3f68c465aba88bdc5e4cd7b98c28181768cdc3..e786f69c65e43f53c4badf91d21c26e0092179b9 100644 (file)
@@ -1,3 +1,30 @@
+2007-04-21  Lamar Goddard <lamargoddard@gmail.com>
+
+        Reviewed by Darin.
+
+        Fix for http://bugs.webkit.org/show_bug.cgi?id=5262
+        <rdar://problem/5018778>
+        XMLSerializer drops Namespace information
+
+        Updated WebCore::markup to output namespace information for elements/attributes whose namespace information
+        doesn't appear in its scope in the output.
+
+        Added test case: fast/dom/serialize-nodes.xhtml
+
+        * WebCore/editing/markup.cpp:
+        (WebCore::createMarkup(const Node*, ...)): Changed call to WebCore::markup to match parameters
+        (WebCore::markup): Changed recursive call to match tree structure, removed ASSERT and no longer needed includeSiblings parameter.
+        (WebCore::startMarkup): Added optional parameter to track namespaces in the current scope.
+        (WebCore::addNamespace): Function to add namespace information to markup.
+        (WebCore::shouldAddNamespaceAttr):
+        (WebCore::shouldAddNamespaceElem): Functions that test whether namespace information should be added for a given node.
+        * WebCore/dom/Document.idl:
+        (createElementNS):
+        (createAttributeNS):
+        (getElementsByTagNameNS): Added [ConvertNullToNullString] to namespaceURI parameter.
+        * WebCore/dom/Node.cpp:
+        (Node::getElementsByTagNameNS): removed test for namespaceURI being null as null can be a valid namespace.
+
 2007-04-21  Alexey Proskuryakov  <ap@webkit.org>
 
         Reviewed by Darin.
index 510b1b83ad81ce91d57bfe8f66506aab138adb13..b35b4878254ae2d69a9bd2aefe4cc4496dccc334 100644 (file)
@@ -49,13 +49,13 @@ module core {
         [OldStyleObjC] Node importNode(in Node importedNode,
                                        in boolean deep)
             raises (DOMException);
-        [OldStyleObjC] Element createElementNS(in DOMString namespaceURI,
+        [OldStyleObjC] Element createElementNS(in [ConvertNullToNullString] DOMString namespaceURI,
                                                in DOMString qualifiedName)
             raises (DOMException);
-        [OldStyleObjC] Attr createAttributeNS(in DOMString namespaceURI,
+        [OldStyleObjC] Attr createAttributeNS(in [ConvertNullToNullString] DOMString namespaceURI,
                                               in DOMString qualifiedName)
             raises (DOMException);
-        [OldStyleObjC] NodeList getElementsByTagNameNS(in DOMString namespaceURI,
+        [OldStyleObjC] NodeList getElementsByTagNameNS(in [ConvertNullToNullString] DOMString namespaceURI,
                                                        in DOMString localName);
         Element            getElementById(in DOMString elementId);
 
index 8e275b77cc5e29825c69bb358e4936ae8d69323b..52c15995107b0ac08b97abfbc383cc0dd775c609 100644 (file)
@@ -1194,7 +1194,7 @@ PassRefPtr<NodeList> Node::getElementsByTagName(const String& name)
  
 PassRefPtr<NodeList> Node::getElementsByTagNameNS(const String &namespaceURI, const String &localName)
 {
-    if (namespaceURI.isNull() || localName.isNull())
+    if (localName.isNull())
         return 0; // FIXME: Who relies on getting 0 instead of a node list in this case?
     
     String name = localName;
index 9f1a26f849bfcd88c4af43529731ff3dec73d6bb..b2039fb973730f0103b1e3ddebc986c000a4b466 100644 (file)
@@ -48,6 +48,7 @@
 #include "KURL.h"
 #include "Logging.h"
 #include "ProcessingInstruction.h"
+#include "QualifiedName.h"
 #include "Range.h"
 #include "Selection.h"
 #include "htmlediting.h"
@@ -154,7 +155,50 @@ static void removeEnclosingMailBlockquoteStyle(CSSMutableStyleDeclaration* style
     blockquoteStyle->diff(style);
 }
 
-static DeprecatedString startMarkup(const Node *node, const Range *range, EAnnotateForInterchange annotate, bool convertBlocksToInlines = false)
+static bool shouldAddNamespaceElem(const Element* elem)
+{
+    // Don't add namespace attribute if it is already defined for this elem.
+    const AtomicString& prefix = elem->prefix();
+    AtomicString attr = !prefix.isEmpty() ? "xmlns:" + prefix : "xmlns";
+    return !elem->hasAttribute(attr);
+}
+
+static bool shouldAddNamespaceAttr(const Attribute* attr, HashMap<AtomicStringImpl*, AtomicStringImpl*>& namespaces)
+{
+    // Don't add namespace attributes twice
+    static const AtomicString xmlnsURI = "http://www.w3.org/2000/xmlns/";
+    static const QualifiedName xmlnsAttr(nullAtom, "xmlns", xmlnsURI);
+    if (attr->name() == xmlnsAttr) {
+        namespaces.set(emptyAtom.impl(), attr->value().impl());
+        return false;
+    }
+    
+    QualifiedName xmlnsPrefixAttr("xmlns", attr->localName(), xmlnsURI);
+    if (attr->name() == xmlnsPrefixAttr) {
+        namespaces.set(attr->localName().impl(), attr->value().impl());
+        return false;
+    }
+    
+    return true;
+}
+
+static String addNamespace(const AtomicString& prefix, const AtomicString& ns, HashMap<AtomicStringImpl*, AtomicStringImpl*>& namespaces)
+{
+    if (ns.isEmpty())
+        return "";
+    
+    // Use emptyAtoms's impl() for both null and empty strings since the HashMap can't handle 0 as a key
+    AtomicStringImpl* pre = prefix.isEmpty() ? emptyAtom.impl() : prefix.impl();
+    AtomicStringImpl* foundNS = namespaces.get(pre);
+    if (foundNS != ns.impl()) {
+        namespaces.set(pre, ns.impl());
+        return " xmlns" + (!prefix.isEmpty() ? ":" + prefix : "") + "=\"" + escapeTextForMarkup(ns.deprecatedString(), true) + "\"";
+    }
+    
+    return "";
+}
+
+static DeprecatedString startMarkup(const Node *node, const Range *range, EAnnotateForInterchange annotate, bool convertBlocksToInlines = false, HashMap<AtomicStringImpl*, AtomicStringImpl*>* namespaces = 0)
 {
     bool documentIsHTML = node->document()->isHTMLDocument();
     switch (node->nodeType()) {
@@ -193,6 +237,8 @@ static DeprecatedString startMarkup(const Node *node, const Range *range, EAnnot
             markup += el->nodeNamePreservingCase().deprecatedString();
             NamedAttrMap *attrs = el->attributes();
             unsigned length = attrs->length();
+            if (!documentIsHTML && namespaces && shouldAddNamespaceElem(el))
+                markup += addNamespace(el->prefix(), el->namespaceURI(), *namespaces).deprecatedString();
 
             for (unsigned int i = 0; i < length; i++) {
                 Attribute *attr = attrs->attributeItem(i);
@@ -206,6 +252,9 @@ static DeprecatedString startMarkup(const Node *node, const Range *range, EAnnot
                 else
                     markup += " " + attr->name().toString().deprecatedString();
                 markup += "=\"" + escapeTextForMarkup(value.deprecatedString(), true) + "\"";
+
+                if (!documentIsHTML && namespaces && shouldAddNamespaceAttr(attr, *namespaces))
+                    markup += addNamespace(attr->prefix(), attr->namespaceURI(), *namespaces).deprecatedString();
             }
             
             if (el->isHTMLElement() && (annotate || convertBlocksToInlines)) {
@@ -274,26 +323,27 @@ static DeprecatedString endMarkup(const Node *node)
     return "";
 }
 
-static DeprecatedString markup(Node* startNode, bool onlyIncludeChildren, bool includeSiblings, Vector<Node*> *nodes)
+static DeprecatedString markup(Node* startNode, bool onlyIncludeChildren, Vector<Node*>* nodes, const HashMap<AtomicStringImpl*, AtomicStringImpl*>* namespaces = 0)
 {
-    // Doesn't make sense to only include children and include siblings.
-    ASSERT(!(onlyIncludeChildren && includeSiblings));
+    HashMap<AtomicStringImpl*, AtomicStringImpl*> namespaceHash;
+    if (namespaces)
+        namespaceHash = *namespaces;
+    
     DeprecatedString me = "";
-    for (Node* current = startNode; current != NULL; current = includeSiblings ? current->nextSibling() : NULL) {
-        if (!onlyIncludeChildren) {
-            if (nodes)
-                nodes->append(current);
-            me += startMarkup(current, 0, DoNotAnnotateForInterchange);
-        }
-        // print children
-        if (Node *n = current->firstChild())
-            if (!(n->document()->isHTMLDocument() && doesHTMLForbidEndTag(current)))
-                me += markup(n, false, true, nodes);
-        
-        // Print my ending tag
-        if (!onlyIncludeChildren)
-            me += endMarkup(current);
+    if (!onlyIncludeChildren) {
+        if (nodes)
+            nodes->append(startNode);
+        me += startMarkup(startNode, 0, DoNotAnnotateForInterchange, false, &namespaceHash);
     }
+    // print children
+    if (!(startNode->document()->isHTMLDocument() && doesHTMLForbidEndTag(startNode)))
+        for (Node* current = startNode->firstChild(); current; current = current->nextSibling())
+            me += markup(current, false, nodes, &namespaceHash);
+    
+    // Print my ending tag
+    if (!onlyIncludeChildren)
+        me += endMarkup(startNode);
+    
     return me;
 }
 
@@ -585,7 +635,7 @@ DeprecatedString createMarkup(const Node* node, EChildrenOnly includeChildren,
     if (node->document()->frame())
         node->document()->frame()->editor()->deleteButtonController()->disable();
     node->document()->updateLayoutIgnorePendingStylesheets();
-    DeprecatedString result(markup(const_cast<Node*>(node), includeChildren, false, nodes));
+    DeprecatedString result(markup(const_cast<Node*>(node), includeChildren, nodes));
     if (node->document()->frame())
         node->document()->frame()->editor()->deleteButtonController()->enable();
     return result;