testing/web-platform/tests/domparsing/XMLSerializer-serializeToString.html
author Kent Tamura <tkent@chromium.org>
Tue, 05 Mar 2019 12:15:16 +0000
changeset 464218 165c390054b242715a5d81c3a47089ec4f6a53e7
parent 464207 7f5ce8587ad9a48d58e387db12b3e022881825d8
child 464219 51f0cd0c1621b937102d5f6969d065cdfa013cbb
permissions -rw-r--r--
Bug 1528721 [wpt PR 15403] - XMLSerializer: Support element prefix rewriting., a=testonly Automatic update from web-platform-tests XMLSerializer: Support element prefix rewriting. We need to change the prefix of an element if: - The element's namespace is same as the inherited default namespace, and the element prefix is not empty, - The prefix-namespace pair of an element is not declared, and there is another prefix associated to the namespace, or - The namespace of an element is not associated to any prefixes, and the element's prefix is declared for another namespace in the element. This CL implements Step 11, 12.1 to 12.5 of [1]. * Add capability to serialize prefix which is not element.prefix() to MarkupFormatter * MarkupAccumulator::AppendElement() returns a serialized prefix, and AppendEndTag() takes it as an argument. * MarkupAccumulator::AppendStartTagOpen() implements the steps, and returns a serialized prefix as well as 'ignore namespace definition attribute' flag. * MarkupAccumulator::RetrievePreferredPrefixString(): Remove the code for empty prefix for elements. Empty prefix is handled in the callsite. * MarkupAccumulator::ShouldAddNamespaceElement(): Removed. It's not used any longer. * dom/domparsing/xmlserializer-xml-namespace-expected.txt: The new behavior is expected. We successfully find 'xml' prefix. [1] https://w3c.github.io/DOM-Parsing/#xml-serializing-an-element-node Bug: 929035 Change-Id: Icf63cb40b120d29a4b8678104592739d773f3a48 Reviewed-on: https://chromium-review.googlesource.com/c/1473090 Reviewed-by: Yoshifumi Inoue <yosin@chromium.org> Commit-Queue: Kent Tamura <tkent@chromium.org> Cr-Commit-Position: refs/heads/master@{#632459} -- wpt-commits: 2767f92702b54d58cd8b4c289f00a7bc028c10fb wpt-pr: 15403

<!DOCTYPE HTML>
<meta charset=utf-8>
<html>
 <head>
  <title>domparsing Test: XMLSerializer.serializeToString</title>
  <script src="/resources/testharness.js"></script>
  <script src="/resources/testharnessreport.js"></script>
 </head>
 <body>
    <h1>domparsing_XMLSerializer_serializeToString</h1>
  <script>
const XMLNS_URI = 'http://www.w3.org/2000/xmlns/';

function createXmlDoc(){
  var input = '<?xml version="1.0" encoding="UTF-8"?><root><child1>value1</child1></root>';
  var parser = new DOMParser();
  return parser.parseFromString(input, 'text/xml');
}

// Returns the root element.
function parse(xmlString) {
  return (new DOMParser()).parseFromString(xmlString, 'text/xml').documentElement;
}

function serialize(node) {
  return (new XMLSerializer()).serializeToString(node);
}

test(function() {
  var serializer = new XMLSerializer();
  var root = createXmlDoc().documentElement;
  var xmlString = serializer.serializeToString(root);
  assert_equals(xmlString, '<root><child1>value1</child1></root>');
}, 'check XMLSerializer.serializeToString method could parsing xmldoc to string');

test(function() {
  var serializer = new XMLSerializer();
  var root = createXmlDoc().documentElement;
  var element = root.ownerDocument.createElementNS('urn:foo', 'another');
  var child1 = root.firstChild;
  root.replaceChild(element, child1);
  element.appendChild(child1);
  var xmlString = serializer.serializeToString(root);
  assert_equals(xmlString, '<root><another xmlns="urn:foo"><child1 xmlns="">value1</child1></another></root>');
}, 'Check if the default namespace is correctly reset.');

test(function() {
  var input = '<root xmlns="urn:bar"><outer xmlns=""><inner>value1</inner></outer></root>';
  var root = (new DOMParser()).parseFromString(input, 'text/xml').documentElement;
  var xmlString = (new XMLSerializer()).serializeToString(root);
  assert_equals(xmlString, '<root xmlns="urn:bar"><outer xmlns=""><inner>value1</inner></outer></root>');
}, 'Check if there is no redundant empty namespace declaration.');

test(function() {
  const root = parse('<root xmlns="uri1"/>');
  const child = root.ownerDocument.createElement('child');
  child.setAttributeNS(XMLNS_URI, 'xmlns', 'FAIL1');
  root.appendChild(child);
  const child2 = root.ownerDocument.createElementNS('uri2', 'child2');
  child2.setAttributeNS(XMLNS_URI, 'xmlns', 'FAIL2');
  root.appendChild(child2);
  const child3 = root.ownerDocument.createElementNS('uri1', 'child3');
  child3.setAttributeNS(XMLNS_URI, 'xmlns', 'FAIL3');
  root.appendChild(child3);
  const child4 = root.ownerDocument.createElementNS('uri4', 'child4');
  child4.setAttributeNS(XMLNS_URI, 'xmlns', 'uri4');
  root.appendChild(child4);
  const child5 = root.ownerDocument.createElement('child5');
  child5.setAttributeNS(XMLNS_URI, 'xmlns', '');
  root.appendChild(child5);
  assert_equals(serialize(root), '<root xmlns="uri1"><child xmlns=""/><child2 xmlns="uri2"/><child3/><child4 xmlns="uri4"/><child5 xmlns=""/></root>');
}, 'Check if inconsistent xmlns="..." is dropped.');

test(function() {
  let root = parse('<r xmlns:xx="uri"></r>');
  root.setAttributeNS('uri', 'name', 'v');
  assert_equals(serialize(root), '<r xmlns:xx="uri" xx:name="v"/>');

  let root2 = parse('<r xmlns:xx="uri"><b/></r>');
  let child = root2.firstChild;
  child.setAttributeNS('uri', 'name', 'v');
  assert_equals(serialize(root2), '<r xmlns:xx="uri"><b xx:name="v"/></r>');

  let root3 = parse('<r xmlns:x0="uri" xmlns:x2="uri"><b xmlns:x1="uri"/></r>');
  let child3 = root3.firstChild;
  child3.setAttributeNS('uri', 'name', 'v');
  assert_equals(serialize(root3),
                '<r xmlns:x0="uri" xmlns:x2="uri"><b xmlns:x1="uri" x1:name="v"/></r>',
                'Should choose the nearest prefix');
}, 'Check if an attribute with namespace and no prefix is serialized with the nearest-declared prefix');

test(function() {
  let root = parse('<el1 xmlns:p="u1" xmlns:q="u1"><el2 xmlns:q="u2"/></el1>');
  root.firstChild.setAttributeNS('u1', 'name', 'v');
  assert_equals(serialize(root),
                '<el1 xmlns:p="u1" xmlns:q="u1"><el2 xmlns:q="u2" q:name="v"/></el1>');
  // Maybe this is a specification error.
}, 'Check if an attribute with namespace and no prefix is serialized with the nearest-declared prefix even if the prefix is assigned to another namespace.');

test(function() {
  let root = parse('<r xmlns:xx="uri"></r>');
  root.setAttributeNS('uri', 'p:name', 'v');
  assert_equals(serialize(root), '<r xmlns:xx="uri" xx:name="v"/>');

  let root2 = parse('<r xmlns:xx="uri"><b/></r>');
  let child = root2.firstChild;
  child.setAttributeNS('uri', 'p:name', 'value');
  assert_equals(serialize(root2),
                '<r xmlns:xx="uri"><b xx:name="value"/></r>');
}, 'Check if the prefix of an attribute is replaced with another existing prefix mapped to the same namespace URI.');

test(function() {
  let root = parse('<r xmlns:xx="uri"></r>');
  root.setAttributeNS('uri2', 'p:name', 'value');
  assert_equals(serialize(root),
                '<r xmlns:xx="uri" xmlns:ns1="uri2" ns1:name="value"/>');
}, 'Check if the prefix of an attribute is NOT preserved in a case where neither its prefix nor its namespace URI is not already used.');

test(function() {
  let root = parse('<r xmlns:xx="uri"></r>');
  root.setAttributeNS('uri2', 'xx:name', 'value');
  assert_equals(serialize(root),
                '<r xmlns:xx="uri" xmlns:ns1="uri2" ns1:name="value"/>');
}, 'Check if the prefix of an attribute is replaced with a generated one in a case where the prefix is already mapped to a different namespace URI.');

test(function() {
  var serializer = new XMLSerializer();
  var parser = new DOMParser();
  var root = parser.parseFromString('<root />', 'text/xml').documentElement;
  root.setAttribute('attr', '\t');
  assert_in_array(serializer.serializeToString(root), [
    '<root attr="&#9;"/>', '<root attr="&#x9;"/>']);
  root.setAttribute('attr', '\n');
  assert_in_array(serializer.serializeToString(root), [
    '<root attr="&#xA;"/>', '<root attr="&#10;"/>']);
  root.setAttribute('attr', '\r');
  assert_in_array(serializer.serializeToString(root), [
    '<root attr="&#xD;"/>', '<root attr="&#13;"/>']);
}, 'check XMLSerializer.serializeToString escapes attribute values for roundtripping');

test(function() {
  const root = (new Document()).createElement('root');
  root.setAttributeNS('uri1', 'p:foobar', 'value1');
  root.setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:p', 'uri2');
  const xmlString = (new XMLSerializer()).serializeToString(root);
  assert_equals(xmlString, '<root xmlns:ns1="uri1" ns1:foobar="value1" xmlns:p="uri2"/>');
}, 'Check if attribute serialization takes into account of following xmlns:* attributes');

test(function() {
  const input = '<root xmlns:p="uri1"><child/></root>';
  const root = (new DOMParser()).parseFromString(input, 'text/xml').documentElement;
  root.firstChild.setAttributeNS('uri2', 'p:foobar', 'v');
  const xmlString = (new XMLSerializer()).serializeToString(root);
  assert_equals(xmlString, '<root xmlns:p="uri1"><child xmlns:ns1="uri2" ns1:foobar="v"/></root>');
}, 'Check if attribute serialization takes into account of the same prefix declared in an ancestor element');

test(function() {
  assert_equals(serialize(parse('<root><child/></root>')), '<root><child/></root>');
  assert_equals(serialize(parse('<root><child xmlns=""/></root>')), '<root><child/></root>');
  assert_equals(serialize(parse('<root xmlns="u1"><child xmlns="u1"/></root>')), '<root xmlns="u1"><child/></root>');
  assert_equals(serialize(parse('<root xmlns="u1"><p:child xmlns:p="u1"/></root>')), '<root xmlns="u1"><child xmlns:p="u1"/></root>');
}, 'Check if start tag serialization drops element prefix if the namespace is same as inherited default namespace.');

test(function() {
  const root = parse('<root xmlns:p1="u1"><child xmlns:p2="u1"/></root>');
  const child2 = root.ownerDocument.createElementNS('u1', 'child2');
  root.firstChild.appendChild(child2);
  assert_equals(serialize(root), '<root xmlns:p1="u1"><child xmlns:p2="u1"><p2:child2/></child></root>');
}, 'Check if start tag serialization finds an appropriate prefix.');

test(function() {
  const root = (new Document()).createElementNS('uri1', 'p:root');
  root.setAttributeNS(XMLNS_URI, 'xmlns:p', 'uri2');
  assert_equals(serialize(root), '<ns1:root xmlns:ns1="uri1" xmlns:p="uri2"/>');
}, 'Check if start tag serialization takes into account of its xmlns:* attributes');

test(function() {
  const root = (new Document()).createElement('root');
  root.setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:p', 'uri2');
  const child = root.ownerDocument.createElementNS('uri1', 'p:child');
  root.appendChild(child);
  assert_equals(serialize(root), '<root xmlns:p="uri2"><p:child xmlns:p="uri1"/></root>');
}, 'Check if start tag serialization applied the original prefix even if it is declared in an ancestor element.');

test(function() {
  const input = '<root><child1/><child2/></root>';
  const root = (new DOMParser()).parseFromString(input, 'text/xml').documentElement;
  root.firstChild.setAttributeNS('uri1', 'attr1', 'value1');
  root.firstChild.setAttributeNS('uri2', 'attr2', 'value2');
  root.lastChild.setAttributeNS('uri3', 'attr3', 'value3');
  const xmlString = (new XMLSerializer()).serializeToString(root);
  assert_equals(xmlString, '<root><child1 xmlns:ns1="uri1" ns1:attr1="value1" xmlns:ns2="uri2" ns2:attr2="value2"/><child2 xmlns:ns3="uri3" ns3:attr3="value3"/></root>');
}, 'Check if generated prefixes match to "ns${index}".');

test(function() {
  const input = '<root xmlns:ns2="uri2"><child xmlns:ns1="uri1"/></root>';
  const root = (new DOMParser()).parseFromString(input, 'text/xml').documentElement;
  root.firstChild.setAttributeNS('uri3', 'attr1', 'value1');
  const xmlString = (new XMLSerializer()).serializeToString(root);
  // According to 'DOM Parsing and Serialization' draft as of 2018-12-11,
  // 'generate a prefix' result can conflict with an existing xmlns:ns* declaration.
  assert_equals(xmlString, '<root xmlns:ns2="uri2"><child xmlns:ns1="uri1" xmlns:ns1="uri3" ns1:attr1="value1"/></root>');
}, 'Check if "ns1" is generated even if the element already has xmlns:ns1.');

test(function() {
  const root = (new Document()).createElement('root');
  root.setAttributeNS('http://www.w3.org/1999/xlink', 'href', 'v');
  assert_equals(serialize(root), '<root xmlns:ns1="http://www.w3.org/1999/xlink" ns1:href="v"/>');

  const root2 = (new Document()).createElement('root');
  root2.setAttributeNS('http://www.w3.org/1999/xlink', 'xl:type', 'v');
  assert_equals(serialize(root2), '<root xmlns:xl="http://www.w3.org/1999/xlink" xl:type="v"/>');
}, 'Check if no special handling for XLink namespace unlike HTML serializer.');

</script>
 </body>
</html>