DOM Parsing and Serialization

DOMParser, XMLSerializer, innerHTML, and similar APIs

W3C Editor's Draft

More details about this document
This version:
https://w3c.github.io/DOM-Parsing/
Latest published version:
https://www.w3.org/TR/DOM-Parsing/
Latest editor's draft:
https://w3c.github.io/DOM-Parsing/
History:
https://www.w3.org/standards/history/DOM-Parsing/
Commit history
Editor:
(Microsoft)
Feedback:
GitHub w3c/DOM-Parsing (pull requests, new issue, open issues)
www-dom@w3.org with subject line DOM-Parsing (archives)
Test Suites
http://wpt.live/domparsing/
http://wpt.live/html/syntax/
Participate
Bugzilla Bug list.
Mailing list.

Abstract

This specification defines APIs for the parsing and serializing of HTML and XML-based DOM nodes for web applications.

Status of This Document

This section describes the status of this document at the time of its publication. A list of current W3C publications and the latest revision of this technical report can be found in the W3C standards and drafts index.

This document was published by the Web Applications Working Group as an Editor's Draft.

Publication as an Editor's Draft does not imply endorsement by W3C and its Members.

This is a draft document and may be updated, replaced, or obsoleted by other documents at any time. It is inappropriate to cite this document as other than a work in progress.

This document was produced by a group operating under the W3C Patent Policy. W3C maintains a public list of any patent disclosures made in connection with the deliverables of the group; that page also includes instructions for disclosing a patent. An individual who has actual knowledge of a patent that the individual believes contains Essential Claim(s) must disclose the information in accordance with section 6 of the W3C Patent Policy.

This document is governed by the 18 August 2025 W3C Process Document.

Candidate Recommendation Exit Criteria

This specification will not advance to Proposed Recommendation before the spec's test suite is completed and two or more independent implementations pass each test, although no single implementation must pass each test. We expect to meet this criteria no sooner than 24 October 2014. The group will also create an Implementation Report.

1. Conformance

As well as sections marked as non-normative, all authoring guidelines, diagrams, examples, and notes in this specification are non-normative. Everything else in this specification is normative.

This specification depends on the Infra Standard. [INFRA]

The IDL fragments in this specification must be interpreted as required for conforming IDL fragments, as described in the Web IDL specification. [WEBIDL]

Requirements phrased in the imperative as part of algorithms (such as "strip any leading space characters" or "return false and terminate these steps") are to be interpreted with the meaning of the key word ("must", "should", "may", etc) used in introducing the algorithm.

Conformance requirements phrased as algorithms or specific steps may be implemented in any manner, so long as the end result is equivalent. (In particular, the algorithms defined in this specification are intended to be easy to follow, and not intended to be performant.)

User agents may impose implementation-specific limits on otherwise unconstrained inputs, e.g. to prevent denial of service attacks, to guard against running out of memory, or to work around platform-specific limitations.

When a method or an attribute is said to call another method or attribute, the user agent must invoke its internal API for that attribute or method so that e.g. the author can't change the behavior by overriding attributes or methods with custom properties or functions in ECMAScript. [ECMA-262]

If an algorithm calls into another algorithm, any exception that is thrown by the latter (unless it is explicitly caught), must cause the former to terminate, and the exception to be propagated up to its caller.

2. Extensibility

Vendor-specific proprietary extensions to this specification are strongly discouraged. Authors must not use such extensions, as doing so reduces interoperability and fragments the user base, allowing only users of specific user agents to access the content in question.

If vendor-specific extensions are needed, the members should be prefixed by vendor-specific strings to prevent clashes with future versions of this specification. Extensions must be defined so that the use of extensions neither contradicts nor causes the non-conformance of functionality defined in the specification.

When vendor-neutral extensions to this specification are needed, either this specification can be updated accordingly, or an extension specification can be written that overrides the requirements in this specification. Such an extension specification becomes an applicable specification for the purposes of conformance requirements in this specification.

3. Introduction

A document object model (DOM) is an in-memory representation of various types of Nodes where each Node is connected in a tree. The [HTML] and [DOM] specifications describe DOM and its Nodes in greater detail.

Parsing is the term used for converting a string representation of a DOM into an actual DOM, and Serializing is the term used to transform a DOM back into a string. This specification concerns itself with defining various APIs for both parsing and serializing a DOM.

For example: the Element.innerHTML API is a common way to both parse and serialize a DOM (it does both). If a particular Node has the following in-memory DOM:
HTMLDivElement (nodeName: "div")
┃
┣━ HTMLSpanElement (nodeName: "span")
┃  ┃
┃  ┗━ Text (data: "some ")
┃
┗━ HTMLElement (nodeName: "em")
   ┃
   ┗━ Text (data: "text!")
And the HTMLDivElement node is stored in a variable myDiv, then to serialize myDiv's children simply get (read) the Element.innerHTML property (this triggers the serialization):
var serializedChildren = myDiv.innerHTML;
// serializedChildren has the value:
// "<span>some </span><em>text!</em>"

To parse new children for myDiv from a string (replacing its existing children), simply set the Element.innerHTML property (this triggers parsing of the assigned string):

myDiv.innerHTML = "<span>new</span><em>children!</em>";

This specification describes two flavors of parsing and serializing: HTML and XML (with XHTML being a type of XML). Each follows the rules of its respective markup language. The above example shows HTML parsing and serialization. The specific algorithms for HTML parsing and serializing are defined in the [HTML] specification. This specification contains the algorithm for XML serializing. The grammar for XML parsing is described in the [XML10] specification.

Round-tripping a DOM means to serialize and then immediately parse the serialized string back into a DOM. Ideally, this process does not result in any data loss with respect to the identity and attributes of the Node in the DOM. Round-tripping is especially tricky for an XML serialization, which must be concerned with preserving the Node's namespace identity in the serialization (wereas namespaces are ignored in HTML).

Consider the XML serialization of the following in-memory DOM:
Element (nodeName: "root")
┃
┗━ HTMLScriptElement (nodeName: "script")
   ┃
   ┗━ Text (data: "alert('hello world')")
An XML serialization must include the HTMLScriptElement's namespace in order to preserve the identity of the script element, and to allow the serialized string to round-trip through an XML parser. Assuming that root is in a variable named root:
var xmlSerialization = new XMLSerializer().serializeToString(root);
// xmlSerialization has the value:
// "<root><script xmlns="http://www.w3.org/1999/xhtml">alert('hello world')</script></root>"

4. APIs for parsing and serializing DOM

4.1 The DOMParser interface

The definition of DOMParser has moved to the HTML Standard.

4.2 The XMLSerializer interface

The definition of XMLSerializer has moved to the HTML Standard.

4.3 The InnerHTML mixin

The definition of Element.innerHTML has moved to the HTML Standard.

4.4 Extensions to the Element interface

The definition of Element.outerHTML has moved to the HTML Standard.

The definition of Element.insertAdjacentHTML has moved to the HTML Standard.

4.5 Extensions to the Range interface

The definition of Range.createContextualFragment() has moved to the HTML Standard.

5. Algorithms for parsing and serializing

5.1 Parsing

The definition of fragment parsing algorithm has moved to the HTML Standard.

5.2 Serializing

The definition of fragment serializing algorithm has moved to the HTML Standard.

5.2.1 XML Serialization

An XML serialization differs from an HTML serialization in the following ways:

  • Elements and attributes will always be serialized such that their namespace is preserved. In some cases this means that an existing prefix, prefix declaration attribute or default namespace declaration attribute might be dropped, substituted or changed. An HTML serialization does not attempt to preserve the namespace.
  • Elements not in the HTML namespace containing no children, are serialized using the empty-element tag syntax (i.e., according to the XML EmptyElemTag production).

Otherwise, the algorithm for producing an XML serialization is designed to produce a serialization that is compatible with the HTML parser. For example, elements in the HTML namespace that contain no children are serialized with an explicit begin and end tag rather than using the empty-element tag syntax.

To produce an XML serialization of a Node node given a boolean require well-formed, run the following steps:

  1. Let namespace be null.

    Note

    namespace tracks the XML serialization algorithm's current default namespace. It is changed when either an Element has a default namespace declaration, or the algorithm generates a default namespace declaration for the Element to match its own namespace. The algorithm assumes no namespace (null) to start.

  2. Let prefix map be «» (a namespace prefix map).
  3. Add "xml" to prefix map given the XML namespace.
  4. Let prefix index be 1.

    Note

    prefix index is used to generate a new unique prefix when no suitable existing namespace prefix is available to serialize a node's namespace (or the namespace of one of the attributes in node's attribute list). See the generate a prefix algorithm.

  5. Return the result of running the XML serialization algorithm given node, namespace, prefix map, a mutable reference to prefix index, and require well-formed. If an exception occurs during the execution of the algorithm, then catch that exception and throw an "InvalidStateError" DOMException.

The XML serialization algorithm, given a Node node, a string namespace, a namespace prefix map prefix map, a mutable reference to an integer prefix index, and a boolean require well-formed, must run the following steps:

  1. If node's interface is:

    Element
    Run the algorithm for XML serializing an Element node given node, namespace, namespace prefix map, prefix index and require well-formed.
    Document
    Run the algorithm for XML serializing a Document node given node, namespace, namespace prefix map, prefix index and require well-formed.
    Comment
    Run the algorithm for XML serializing a Comment node given node and require well-formed.
    CDATASection
    Run the algorithm for XML serializing a CDATASection node given node and require well-formed.
    Text
    Run the algorithm for XML serializing a Text node given node and require well-formed.
    DocumentFragment
    Run the algorithm for XML serializing a DocumentFragment node given node, namespace, namespace prefix map, prefix index and require well-formed.
    DocumentType
    Run the algorithm for XML serializing a DocumentType node given node and require well-formed.
    ProcessingInstruction
    Run the algorithm for XML serializing a ProcessingInstruction node given node and require well-formed.
    Attr
    Return the empty string.
    Anything else
    Throw a TypeError. Only Nodes and Attrs can be serialized by this algorithm.
Note

Each of the above referenced algorithms are detailed in the sections that follow.

5.2.1.1 XML serializing an Element node

The algorithm for XML serializing an Element node, given an Element node, a string namespace, a namespace prefix map prefix map, a mutable reference to an integer prefix index, and a boolean require well-formed, must run the following steps:

  1. If require well-formed is true, and node's local name contains the character ":" (U+003A COLON) or does not match the XML Name production, then throw an exception. (The serialization of node would not be well-formed.)
  2. Let markup be "<" (U+003C LESS-THAN SIGN).
  3. Let qualified name be the empty string.
  4. Let skip end tag be false.
  5. Let ignore namespace definition attribute be false.
  6. Let map be the result of copy a namespace prefix map given prefix map.
  7. Let local prefixes map be « » (an ordered map from strings to strings).

    Note

    Its keys will be prefixes, and its values will be namespaces. In this map, the null namespace is represented by the empty string.

    Note

    This map is local to each element. It is used to ensure there are no conflicting prefixes if a new namespace prefix attribute needs to be generated. It is also used to enable skipping of duplicate prefix definitions when writing an element's attributes: the map allows the algorithm to distinguish between a prefix in the namespace prefix map that might be locally-defined (to the current Element) and one that is not.

  8. Let local default namespace be the result of recording the namespace information for node's attribute list given map and local prefixes map.
    Note

    The above step will update map with any found namespace prefix definitions, add the found prefix definitions to local prefixes map and return the value of a default namespace attribute (which can be empty) if one exists. Otherwise it returns null.

  9. Let inherited ns be namespace.
    Note

    inherited ns will be passed down as the namespace argument when serializing node's children.

  10. Let ns be node's namespace.
  11. If inherited ns is ns, then:
    Note

    node is in the current default namespace. The steps below serialize node without a prefix (even if it had one), and drop any default namespace declaration. An exception is made if node is in the XML namespace, in which case the "xml:" prefix is used; this prefix does not need to be declared and no effort is made to declare it.

    1. If local default namespace is not null, then set ignore namespace definition attribute to true.
    2. If ns is the XML namespace, then append the concatenation of "xml:" and node's local name to qualified name.
    3. Otherwise, append node's local name to qualified name.
    4. Append qualified name to markup.
  12. Otherwise:
    Note

    inherited ns is not equal to ns; node's own namespace is different from the context namespace. To differentiate node's namespace from the context namespace, the steps below will use a namespace prefix if one is available; if not, they will use or introduce a default namespace declaration.

    1. Let prefix be node's namespace prefix.
    2. Let candidate prefix be the result of retrieving a preferred prefix string prefix from map given ns.
      Note

      candidate prefix will be null if no prefix was found that maps to ns (not even prefix). In that case, this algorithm will generate a new xmlns attribute and add any new prefix to map below.

    3. If prefix is "xmlns", then:
      1. If require well-formed is true, then throw an exception. An Element with namespace prefix "xmlns" will not legally round-trip in a conforming XML parser.
      2. Set candidate prefix to prefix.
    4. Found a suitable namespace prefix: if candidate prefix is not null, then:
      Note

      Either node or one of its ancestors defines that candidate prefix maps to node's namespace.

      Note

      The following could serialize a different prefix than node's existing namespace prefix, if any. However, this only happens if this prefix does not map to the correct namespace, as the retrieving a preferred prefix string algorithm already tried to match the existing prefix.

      Issue 52: XMLSerializer: Should prefer the default namespace to a prefix declared in an ancestor xml-serialization

      Suppose that we have the following XML document, parse it, and serialize it.

      <root xmlns:x="uri1">
       <table xmlns="uri1"/>
      </root>

      If we follow the current specification, the serialization result is:

      <root xmlns:x="uri1">
       <x:table xmlns="uri1"/>
      </root>

      It's incompatible with Edge, Firefox, Safari, and Chrome 73-.
      (Chrome 74 produces the above result, and we're fixing it.)

      I think 12.1 in https://w3c.github.io/DOM-Parsing/#xml-serializing-an-element-node should be changed as following:

      Original: Let candidate prefix be the result of retrieving a preferred prefix string prefix from map given namespace ns.

      Proposed: Let candidate prefix be null if prefix is null and ns equals to local default namespace. Otherwise let candidate prefix be the result of retrieving a preferred prefix string prefix from map given namespace ns.

      WPT domparsing/XMLSerializer-serializeToString.html contains a testcase for this behavior.
      "Check if start tag serialization does NOT apply the default namespace if its namespace is declared in an ancestor."

      1. Append the concatenation of candidate prefix, ":" (U+003A COLON), and node's local name to qualified name.
      2. If local default namespace is not null (node has a default namespace declaration attribute) and is not the XML namespace, then:
        1. If local default namespace is the empty string, set inherited ns to null.
        2. Otherwise, set inherited ns to local default namespace.
        Note

        It is possible that inherited ns differs from node's namespace.

        Note

        Any default namespace definitions or namespace prefixes that define the XML namespace are omitted when serializing attributes in node's attribute list.

      3. Append qualified name to markup.
    5. Otherwise, if prefix is not null, then:
      Note

      By this step, there is no namespace or prefix mapping declaration in node (or any parent Node visited by this algorithm) that defines a prefix that maps to node's namespace; otherwise the step labelled Found a suitable namespace prefix would have been followed. Ideally we would use node's namespace prefix. However, it could be the case that node already declares its own prefix as mapping to something else than its own namespace. In that case we will generate a new prefix as a last resort. In either case, the sub-steps that follow will serialize a new namespace prefix declaration for the prefix we end up using.

      1. If local prefixes map contains prefix, then set prefix to the result of generating a prefix given map, ns, and prefix index.
      2. Add prefix to map given ns.
      3. Append the concatenation of prefix, ":" (U+003A COLON), and node's local name to qualified name.
      4. Append qualified name to markup.
      5. Append the following to markup, in the order listed:
        Note

        The following serializes a namespace prefix declaration for prefix which was just added to map.

        1. " " (U+0020 SPACE);
        2. "xmlns:";
        3. prefix;
        4. "="" (U+003D EQUALS SIGN, U+0022 QUOTATION MARK);
        5. The result of serializing an attribute value given ns and require well-formed;
        6. """ (U+0022 QUOTATION MARK).
      6. If local default namespace is not null (node has a default namespace declaration attribute), then:
        1. If local default namespace is the empty string, set inherited ns to null.
        2. Otherwise, set inherited ns to local default namespace.
    6. Otherwise, if local default namespace is null, or local default namespace is not null and its value is not equal to ns, then:
      Note

      At this point, the namespace for this node still needs to be serialized, but there's no namespace prefix (or candidate prefix) available; the following uses the default namespace declaration to define the namespace—optionally replacing an existing default declaration if present.

      1. Set ignore namespace definition attribute to true.
      2. Append node's local name to qualified name.
      3. Set inherited ns to ns.
        Note

        The new default namespace will be used in the serialization to define node's namespace and act as the context namespace for its children.

      4. Append qualified name to markup.
      5. Append the following to markup, in the order listed:
        Note

        The following serializes the new (or replacement) default namespace definition.

        1. " " (U+0020 SPACE);
        2. "xmlns";
        3. "="" (U+003D EQUALS SIGN, U+0022 QUOTATION MARK);
        4. The result of serializing an attribute value given ns and require well-formed;
        5. """ (U+0022 QUOTATION MARK).
    7. Otherwise:
      Note

      local default namespace is ns.

      1. Append node's local name to qualified name.
      2. Set inherited ns to ns.
      3. Append qualified name to markup.
      Note

      All of the combinations where ns is not equal to inherited ns are handled above such that node will be serialized preserving its original namespace.

  13. Append to markup the result of the XML serialization of the attributes of node given map, prefix index, local prefixes map, ignore namespace definition attribute, and require well-formed.
  14. If ns is the HTML namespace, and node's children is empty, and node's local name is one of the following: "area", "base", "basefont", "bgsound", "br", "col", "embed", "frame", "hr", "img", "input", "keygen", "link", "menuitem", "meta", "param", "source", "track", "wbr"; then append the following to markup, in the order listed:
    1. " " (U+0020 SPACE);
    2. "/" (U+002F SOLIDUS).
    and set skip end tag to true.
  15. If ns is not the HTML namespace, and node's children is empty, then append "/" (U+002F SOLIDUS) to markup and set skip end tag to true.
  16. Append ">" (U+003E GREATER-THAN SIGN) to markup.
  17. If skip end tag is true, then return markup. node is a leaf node.
  18. If ns is the HTML namespace, and node's local name is "template" (this is a template element), append to markup the result of XML serializing a DocumentFragment node given node's template contents (a DocumentFragment), inherited ns, map, prefix index, and require well-formed.
    Note

    This allows template content to round-trip, given the rules for parsing XHTML documents.

  19. Otherwise, for each child of node's children:

    1. Append to markup the result of running the XML serialization algorithm given child, inherited ns, map, prefix index, and require well-formed.
  20. Append the following to markup, in the order listed:
    1. "</" (U+003C LESS-THAN SIGN, U+002F SOLIDUS);
    2. qualified name;
    3. ">" (U+003E GREATER-THAN SIGN).
  21. Return markup.
5.2.1.1.1 Recording the namespace
Note

This following algorithm will update the namespace prefix map with any found namespace prefix definitions, add the found prefix definitions to local prefixes map, and return a local default namespace value defined by a default namespace attribute if one exists. Otherwise it returns null.

When recording the namespace information for a list of attributes attributes, given a namespace prefix map map and an ordered map local prefixes map, run the following steps:

  1. Let default namespace attr value be null.
  2. For each attr of attributes:
    Note

    The following conditional steps find namespace prefixes. Only attributes in the XMLNS namespace are considered (e.g., attributes made to look like namespace declarations via setAttribute("xmlns:pretend-prefix", "pretend-namespace") are not included).

    1. Let attribute namespace be attr's namespace.
    2. Let attribute prefix be attr's namespace prefix.
    3. If attribute namespace is the XMLNS namespace, then:
      1. If attribute prefix is null (attr is a default namespace declaration), set default namespace attr value to attr's value, and continue.
      2. Otherwise:
          Note
        1. attribute prefix is not null and attr is a namespace prefix definition.
        2. Let prefix definition be attr's local name.
        3. Let namespace definition be attr's value.
        4. If namespace definition is the XML namespace, then continue.
          Note

          XML namespace definitions in prefixes are completely ignored (in order to avoid unnecessary work when there might be prefix conflicts). Elements in the XML namespace are always handled uniformly by prefixing (and overriding if necessary) the element's local name with the reserved "xml" prefix.

        5. If namespace definition is the empty string (the declarative form of having no namespace), then set namespace definition to null.
        6. If prefix definition is found in map given namespace definition, then continue.
          Note

          This step avoids adding duplicate prefix definitions for the same namespace in map. This has the side-effect of avoiding later serialization of duplicate namespace prefix declarations in any descendant nodes.

        7. Add prefix definition to map given namespace definition.
        8. If namespace definition is null, then set namespace definition to the empty string.
        9. Set local prefixes map[prefix definition] to namespace definition.
  3. Return default namespace attr value.
    Note

    The empty string is a legitimate return value and is not converted to null.

5.2.1.1.2 The Namespace Prefix Map

A namespace prefix map is an ordered map from strings or null to lists of strings.

Note

The keys are namespaces, with null representing no namespace; the values are lists of prefixes that map to that namespace.

An empty namespace prefix map will be created at the start of the XML serialization algorithm. Whenever a new Element is encountered, the map will be cloned (copy a namespace prefix map) and new associations will be added for that Element (primarily in recording the namespace information, but also when adding new namespace declarations because no prefix is available for a particular namespace).

The last seen prefix for a given namespace is at the end of its respective list. When serializing, the Element's namespace prefix will be used if it is in the list; otherwise the last prefix in the list is used. See retrieve a preferred prefix string for additional details.

To copy a namespace prefix map map:

  1. Let copy be a new namespace prefix map.
  2. For each key → value in map:

    1. Set copy[key] to a clone of value.
  3. Return copy.

To retrieve a preferred prefix string preferred prefix (a string or null) from the namespace prefix map map given a namespace ns:

  1. If map does not contain ns, return null.
  2. Let candidates be map[ns].
  3. Assert: candidates is not empty.
  4. If prefix is not null, then:

    1. For each prefix of candidates:

      1. If prefix is preferred prefix, return prefix.
  5. Return candidates[size of candidates - 1].

To check if a string prefix is found in a namespace prefix map map given a namespace ns:

  1. If map does not contain ns, return false.
  2. Let candidates be map[ns].
  3. If candidates contains prefix, return true, otherwise return false.

To add a string prefix to a namespace prefix map map given a namespace ns:

  1. If map does not contain ns:

    1. Let candidates be « prefix ».
    2. Set map[ns] to candidates.
  2. Otherwise:

    1. Let candidates be map[ns].
    2. Append prefix to candidates.
Note

The steps in retrieve a preferred prefix string use the list to track the most recently used prefix associated with a given namespace, which will be the prefix at the end of the list. This list can contain duplicates of the same prefix seen earlier (and that's OK).

5.2.1.1.3 Serializing an Element's attributes

The XML serialization of the attributes of an Element element given a namespace prefix map map, a mutable reference to an integer prefix index, an ordered map local prefixes map, a boolean ignore namespace definition attribute, and a boolean require well-formed, is the result of the following algorithm:

  1. Let result be the empty string.
  2. Let localname set be « » (an empty ordered set).
    Note

    localname set will contain tuples of unique attribute (namespace, local name) pairs, and is populated as each attr is processed. If require well-formed is true, it is used to enforce the well-formed constraint that an element cannot have two attributes with the same namespace and local name. This can occur when two otherwise identical attributes on the same element differ only by their prefix values. If require well-formed is false, localname set is unnecessary.

  3. For each attr of element's attribute list:
    1. Let attribute namespace be attr's namespace.
    2. Let attrName be a new tuple (attribute namespace, attr's local name).
    3. If require well-formed is true, and localname set contains attrName, then throw an exception. The serialization of attr would not be well-formed.
    4. Append attrName to localname set.
    5. Let candidate prefix be null.
    6. If attribute namespace is not null, then:
      1. Let prefix be attr's namespace prefix.
      2. Set candidate prefix to the result of retrieving a preferred prefix string prefix from map given attribute namespace.
      3. If attribute namespace is the XMLNS namespace, then:
        1. If any of the following are true, then continue:
          • attr's value is the XML namespace;
            Note

            The XML namespace cannot be redeclared and survive round-tripping (unless it defines the prefix "xml"). To avoid this problem, this algorithm always prefixes elements in the XML namespace with "xml" and drops any related definitions as seen in the above condition.

          • prefix is null and ignore namespace definition attribute is true (the Element's default namespace attribute is to be skipped);
          • prefix is not null and either and furthermore that attr's local name is found in map given attr's value (the current namespace prefix definition was exactly defined previously—on an ancestor element, not element).
        2. If require well-formed is true, and attr's value is the XMLNS namespace, then throw an exception. The serialization of this attribute would produce invalid XML because the XMLNS namespace is reserved and cannot be applied as an element's namespace via XML parsing.
          Note

          DOM APIs do allow creation of elements in the XMLNS namespace but with strict qualifications.

        3. If require well-formed is true, and attr's value is the empty string, then throw an exception. Namespace prefix declarations cannot be used to undeclare a namespace (use a default namespace declaration instead).
        4. If prefix is "xmlns", then set candidate prefix to "xmlns".
      4. Otherwise (attribute namespace is not the XMLNS namespace), if candidate prefix is null:
        1. If prefix is not null and local prefixes map does not contain prefix, set candidate prefix to prefix.
        2. Otherwise, set candidate prefix to the result of generating a prefix given map, attribute namespace, and prefix index.
        3. Add candidate prefix to map given attribute namespace.
        4. Let map value be the empty string if attribute namespace is null, and attribute namespace otherwise.
        5. Set local prefixes map[candidate prefix] to map value.
        6. Append the following to result, in the order listed:
          1. " " (U+0020 SPACE);
          2. "xmlns:";
          3. candidate prefix;
          4. "="" (U+003D EQUALS SIGN, U+0022 QUOTATION MARK);
          5. The result of serializing an attribute value given attribute namespace and require well-formed;
          6. """ (U+0022 QUOTATION MARK).
    7. Append " " (U+0020 SPACE) to result.
    8. If candidate prefix is not null, then append to result the concatenation of candidate prefix and ":" (U+003A COLON).
    9. If require well-formed is true, and attr's local name contains the character ":" (U+003A COLON) or does not match the XML Name production or equals "xmlns" and attribute namespace is null, then throw an exception. The serialization of attr would not be well-formed.
    10. Append the following to result, in the order listed:
      1. attr's local name;
      2. "="" (U+003D EQUALS SIGN, U+0022 QUOTATION MARK);
      3. The result of serializing an attribute value given attr's value and require well-formed;
      4. """ (U+0022 QUOTATION MARK).
  4. Return result.

When serializing an attribute value given a string or null attribute value and a boolean require well-formed, run the following steps:

  1. If require well-formed is true, and attribute value contains characters that are not matched by the XML Char production, then throw an exception. The serialization of attribute value would not be well-formed.
  2. If attribute value is null, then return the empty string.
  3. Otherwise, return attribute value, first replacing any occurrences of the following:
    1. "&" with "&amp;"
    2. """ with "&quot;"
    3. "<" with "&lt;"
    4. U+0009 CHARACTER TABULATION with "&#9;"
    5. U+000A LINE FEED (LF) with "&#xA;"
    6. U+000D CARRIAGE RETURN (CR) with "&#xD;"
    Note

    This matches behavior present in browsers, and goes above and beyond the grammar requirement in the XML specification's AttValue production by also replacing ">" characters.

5.2.1.1.4 Generating namespace prefixes

To generate a prefix given a namespace prefix map map, a string new namespace, and a mutable reference to an integer prefix index:

  1. Let generated prefix be the concatenation of "ns" and the current numerical value of prefix index.
  2. Increment the value of prefix index by one.
  3. Add generated prefix to map given new namespace.
  4. Return the value of generated prefix.
Issue 44: It's possible for 'generate a prefix' algorithm to generate a prefix conflicting with an existing one xml-serialization

https://w3c.github.io/DOM-Parsing/#generating-namespace-prefixes

The algorithm just generates 'ns1', 'ns2', ... without checking existence of generated prefixes.
So, the following example serializes two xmlns:ns1 on child element if we follow the current specification. WPT domparsing/XMLSerializer-serializeToString.html already has a test case ("Check if "ns1" is generated even if the element already has xmlns:ns1.").

const root = (new DOMParser()).parseFromString('<root xmlns:ns2="uri2"><child xmlns:ns1="uri1" xmlns:a0="uri1" xmlns:NS1="uri1"/></root>', 'text/xml').documentElement;
root.firstChild.setAttributeNS('uri3', 'attr1', 'value1');
console.log((new XMLSerializer()).serializeToString(root));

The algorithm should have a loop until a generated prefix is not found.

5.2.1.2 XML serializing a Document node

The algorithm for XML serializing a Document node, given a Document node, a string namespace, a namespace prefix map prefix map, a mutable reference to an integer prefix index, and a boolean require well-formed, must run the following steps:

  1. If require well-formed is true, and node's document element is null, then throw an exception. The serialization of node would not be well-formed.
  2. Otherwise:
    1. Let serialized document be the empty string.
    2. For each child of node's children:

      1. Append to serialized document the result of running the XML serialization algorithm given child, inherited ns, map, prefix index, and require well-formed.
      Note

      This will serialize any number of ProcessingInstruction and Comment nodes both before and after the document element, as well as at most one DocumentType node. (Text nodes are not allowed as children of a Document.)

    3. Return serialized document.
5.2.1.3 XML serializing a Comment node

The algorithm for XML serializing a Comment node, given a Comment node, and a boolean require well-formed, must run the following steps:

  1. If require well-formed is true, and node's data contains characters that are not matched by the XML Char production or contains "--" (two adjacent U+002D HYPHEN-MINUS characters) or ends with a "-" (U+002D HYPHEN-MINUS) character, then throw an exception. The serialization of node would not be well-formed.
  2. Otherwise, return the concatenation of "<!--", node's data, and "-->".
5.2.1.4 XML serializing a CDATASection node

The algorithm for XML serializing a CDATASection node, given a CDATASection node, and a boolean require well-formed, must run the following steps:

  1. Let markup be the concatenation of "<![CDATA[", node's data, and "]]>".
  2. Return markup.
5.2.1.5 XML serializing a Text node

The algorithm for XML serializing a Text node, given a Text node, and a boolean require well-formed, must run the following steps:

  1. Let markup be node's data.
  2. If require well-formed is true, and markup contains characters that are not matched by the XML Char production, then throw an exception. The serialization of node would not be well-formed.
  3. Replace any occurrences of "&" in markup by "&amp;".
  4. Replace any occurrences of "<" in markup by "&lt;".
  5. Replace any occurrences of ">" in markup by "&gt;".
  6. Return markup.
5.2.1.6 XML serializing a DocumentFragment node

The algorithm for XML serializing a DocumentFragment node, given a DocumentFragment node, a string namespace, a namespace prefix map prefix map, a mutable reference to an integer prefix index, and a boolean require well-formed, must run the following steps:

  1. Let markup be the empty string.
  2. For each child of node's children:

    1. Append to markup the result of running the XML serialization algorithm given child, inherited ns, map, prefix index, and require well-formed.
  3. Return markup.
5.2.1.7 XML serializing a DocumentType node

The algorithm for XML serializing a DocumentType node, given a DocumentType node, and a boolean require well-formed, must run the following steps:

  1. If require well-formed is true, and node's public ID contains characters that are not matched by the XML PubidChar production, then throw an exception. The serialization of node would not be well-formed.
  2. If require well-formed is true, and node's system ID contains characters that are not matched by the XML Char production or that contains both a """ (U+0022 QUOTATION MARK) and a "'" (U+0027 APOSTROPHE), then throw an exception. The serialization of node would not be well-formed.
  3. Let markup be the empty string.
  4. Append "<!DOCTYPE" to markup.
  5. Append " " (U+0020 SPACE) to markup.
  6. Append node's name to markup. For a node belonging to an HTML document, the name will be all lowercase.
  7. If node's public ID is not the empty string, then append the following, in the order listed, to markup:
    1. " " (U+0020 SPACE);
    2. "PUBLIC";
    3. " " (U+0020 SPACE);
    4. the serialization of the ID node's public ID.
  8. If node's system ID is not the empty string and node's public ID is the empty string, then append the following, in the order listed, to markup:
    1. " " (U+0020 SPACE);
    2. "SYSTEM".
  9. If node's system ID is not the empty string, then append the following, in the order listed, to markup:
    1. " " (U+0020 SPACE);
    2. the serialization of the ID node's system ID.
  10. Append ">" (U+003E GREATER-THAN SIGN) to markup.
  11. Return markup.

The serialization of the ID id is the result of the following steps:

  1. If id contains """ (U+0022 QUOTATION MARK), let q be "'" (U+0027 APOSTROPHE), and let q be """ (U+0022 QUOTATION MARK) otherwise.
  2. Return the concatenation of q, id, and q.
5.2.1.8 XML serializing a ProcessingInstruction node

The algorithm for XML serializing a ProcessingInstruction node, given a ProcessingInstruction node, and a boolean require well-formed, must run the following steps:

  1. If require well-formed is true, and node's target contains a ":" (U+003A COLON) character or is an ASCII case-insensitive match for "xml", then throw an exception. The serialization of node would not be well-formed.
  2. If require well-formed is true, and node's data contains characters that are not matched by the XML Char production or contains "?>" (U+003F QUESTION MARK, U+003E GREATER-THAN SIGN), then throw an exception. The serialization of node would not be well-formed.
  3. Let markup be the concatenation of the following, in the order listed:
    1. "<?" (U+003C LESS-THAN SIGN, U+003F QUESTION MARK);
    2. node's target;
    3. " " (U+0020 SPACE);
    4. node's data;
    5. "?>" (U+003F QUESTION MARK, U+003E GREATER-THAN SIGN).
  4. Return markup.

A. Dependencies

The HTML specification [HTML] defines the following terms used in this document: The following terms used in this document are defined by [XML10]:

B. Revision History

The following is an informative summary of the changes since the last publication of this specification. A complete revision history of the Editor's Drafts of this specification can be found at the W3C Github Repository and older revisions at the W3C Mercurial server.

C. Acknowledgements

We acknowledge with gratitude the original work of Ms2ger and others at the WHATWG, who created and maintained the original DOM Parsing and Serialization Living Standard upon which this specification is based.

Thanks to C. Scott Ananian, Victor Costan, Aryeh Gregor, Anne van Kesteren, Arkadiusz Michalski, Simon Pieters, Henri Sivonen, Josh Soref and Boris Zbarsky, for their useful comments.

Special thanks to Ian Hickson for first defining the innerHTML and outerHTML attributes, and the insertAdjacentHTML method in [HTML] and his useful comments.

D. References

D.1 Normative references

[DOM]
DOM Standard. Anne van Kesteren. WHATWG. Living Standard. URL: https://dom.spec.whatwg.org/
[ECMA-262]
ECMAScript Language Specification. Ecma International. URL: https://tc39.es/ecma262/multipage/
[HTML]
HTML Standard. Anne van Kesteren; Domenic Denicola; Dominic Farolino; Ian Hickson; Philip Jägenstedt; Simon Pieters. WHATWG. Living Standard. URL: https://html.spec.whatwg.org/multipage/
[INFRA]
Infra Standard. Anne van Kesteren; Domenic Denicola. WHATWG. Living Standard. URL: https://infra.spec.whatwg.org/
[WEBIDL]
Web IDL Standard. Edgar Chen; Timothy Gu. WHATWG. Living Standard. URL: https://webidl.spec.whatwg.org/
[XML10]
Extensible Markup Language (XML) 1.0 (Fifth Edition). Tim Bray; Jean Paoli; Michael Sperberg-McQueen; Eve Maler; François Yergeau et al. W3C. 26 November 2008. W3C Recommendation. URL: https://www.w3.org/TR/xml/