Web DOM Core

Work in Progress — Last Update [DATE: 01 Jan 1901]

Editor
Simon Pieters <simonp@opera.com>

Issues

Abstract

This specification defines the DOM Core part of the Web platform. The Document Object Model is a language- and platform neutral interface that allows programs and scripts to dynamically access and update the content, structure and style of documents. Web DOM Core mostly subsets DOM3 Core, but redefines some things and adds some features that were widely implemented already.

Table of contents

Common infrastructure

Terminology

The term tree order means a pre-order, depth-first traversal of DOM nodes involved (through the parentNode/childNodes relationship).

The term context node means the Node on which the method or attribute being discussed was called.

Conformance requirements

RFC2119, WebIDL, HTML5.

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.

Unless otherwise stated, string comparisons are done in a case-sensitive manner.

Case-sensitivity

This specification defines several comparison operators for strings.

Comparing two strings in a case-sensitive manner means comparing them exactly, codepoint for codepoint.

Comparing two strings in a ASCII case-insensitive manner means comparing them exactly, codepoint for codepoint, except that the characters in the range U+0041 .. U+005A (i.e. LATIN CAPITAL LETTER A to LATIN CAPITAL LETTER Z) and the corresponding characters in the range U+0061 .. U+007A (i.e. LATIN SMALL LETTER A to LATIN SMALL LETTER Z) are considered to also match.

Converting a string to uppercase means replacing all characters in the range U+0061 .. U+007A (i.e. LATIN SMALL LETTER A to LATIN SMALL LETTER Z) with the corresponding characters in the range U+0041 .. U+005A (i.e. LATIN CAPITAL LETTER A to LATIN CAPITAL LETTER Z).

Converting a string to lowercase means replacing all characters in the range U+0041 .. U+005A (i.e. LATIN CAPITAL LETTER A to LATIN CAPITAL LETTER Z) with the corresponding characters in the range U+0061 .. U+007A (i.e. LATIN SMALL LETTER A to LATIN SMALL LETTER Z).

DOM features

Features are ASCII case-insensitive. Empty string means any version.

Suggest how specs are to define feature strings.

Cloning nodes

When a UA is to clone a node, with a new ownerDocument and with a clone children flag, it must run the following steps:

  1. If node is a DocumentType node, raise a NOT_SUPPORTED_ERR exception and abort these steps.

  2. Let copy be a new Node that implements the same interfaces as node, with ownerDocument set to new ownerDocument, prefix, localName and namespaceURI attributes set to the values of the attributes on node with the same names, and other attributes set to the values of the attributes on node with the same names depending on the type of node according to the following table:

    Type of nodeAttributes
    Element
    Attrvalue
    Textdata
    ProcessingInstructiontarget, data
    Commentdata
    DocumentFragment
  3. If node is an Element node, copy its attributes.

  4. If the clone children flag is set, clone all the children of node and append them to copy, with the same new ownerDocument and the clone children flag being set.

  5. Return copy.

Legal hierarchy

A Node is said to have a legal hierarchy if all the following conditions are true:

Before running the steps of an algorithm of a method or attribute in this specification, the user agent must check that running the algorithm will result in a legal hierarchy. If it won't, then the user agent must instead raise a HIERARCHY_REQUEST_ERR exception.

Basic types

A DOMTimeStamp represents a number of milliseconds.

typedef unsigned long long DOMTimeStamp;

Interfaces

Exception DOMException

[ExceptionConsts=DOMException]
module domexception {
  exception DOMException {
    unsigned short code;
    DOMString message;
    DOMString name;
  };
  const unsigned short INDEX_SIZE_ERR = 1;
  const unsigned short DOMSTRING_SIZE_ERR = 2;
  const unsigned short HIERARCHY_REQUEST_ERR = 3;
  const unsigned short WRONG_DOCUMENT_ERR = 4;
  const unsigned short INVALID_CHARACTER_ERR = 5;
  const unsigned short NO_DATA_ALLOWED_ERR = 6;
  const unsigned short NO_MODIFICATION_ALLOWED_ERR = 7;
  const unsigned short NOT_FOUND_ERR = 8;
  const unsigned short NOT_SUPPORTED_ERR = 9;
  const unsigned short INUSE_ATTRIBUTE_ERR = 10;
  const unsigned short INVALID_STATE_ERR = 11;
  const unsigned short SYNTAX_ERR = 12;
  const unsigned short INVALID_MODIFICATION_ERR = 13;
  const unsigned short NAMESPACE_ERR = 14;
  const unsigned short INVALID_ACCESS_ERR = 15;
  const unsigned short VALIDATION_ERR = 16;
  const unsigned short TYPE_MISMATCH_ERR = 17;
  const unsigned short SECURITY_ERR = 18;
  const unsigned short NETWORK_ERR = 19;
  const unsigned short ABORT_ERR = 20;
  const unsigned short URL_MISMATCH_ERR = 21;
  const unsigned short QUOTA_EXCEEDED_ERR = 22;
  const unsigned short DATAGRID_MODEL_ERR = 23;
};

The code exception member must return the code for the exception, which must be one of the following:

...
...

The message exception member must return ...

The name exception member must return ...

Interface DOMImplementation

User agents must create a new DOMImplementation object whenever a new Document node is created and associate it with the that Document node.

interface DOMImplementation {
  boolean hasFeature(in DOMString feature, [Null=Empty] in DOMString version);
  DocumentType createDocumentType([Null=Empty] in DOMString qualifiedName, in DOMString publicId, in DOMString systemId);
  Document createDocument([Null=Empty] in DOMString namespaceURI, [Null=Empty] in DOMString qualifiedName, in DocumentType doctype);
};

The hasFeature(feature, version) method must return true if the UA supports the given feature feature of version version, and false otherwise.

The createDocumentType(qualifiedName, publicId, systemId) method must run the following steps:

  1. If qualifiedName doesn't match the Name production in XML, raise an INVALID_CHARACTER_ERR exception and abort these steps. [XML]

  2. If qualifiedName doesn't match the NCName production in Namespaces in XML, raise a NAMESPACE_ERR exception and abort these steps. [XMLNS]

  3. Return a new DocumentType node with ownerDocument set to null, name set to qualifiedName, publicId set to publicId, and systemId set to systemId.

No check is performed that the publicId matches the PublicChar production in XML or that the systemId doesn't contain both a quotation mark (") and an apostrophe (').

The createDocument(namespaceURI, qualifiedName, doctype) method must run the following steps:

  1. Let document be a new Document node.

  2. Let element be null.

  3. If qualifiedName is not the empty string, set element to the result of invoking the createElementNS method with the arguments namespaceURI and qualifiedName on document. If that raised an exception, re-raise the same exception and abort these steps.

  4. If doctype is not null, run the following substeps:

    1. If the doctype's ownerDocument is not null or if doctype was created from a different DOMImplementation, then raise a WRONG_DOCUMENT_ERR exception and abort the overall set of steps.

    2. Set the doctype's ownerDocument to document.

    3. Append doctype to document.

  5. If element is not null, append element to document.

  6. Return document.

Interface DocumentFragment

interface DocumentFragment : Node {
};

Interface Document

interface Document : Node {
  readonly attribute DocumentType doctype;
  readonly attribute DOMImplementation implementation;
  readonly attribute Element documentElement;
  Element createElement(in DOMString tagName);
  DocumentFragment createDocumentFragment();
  Text createTextNode(in DOMString data);
  Comment createComment(in DOMString data);
  ProcessingInstruction createProcessingInstruction(in DOMString target, in DOMString data);
  NodeList getElementsByTagName(in DOMString tagname);
  Node importNode(in Node importedNode, in boolean deep);
  Element createElementNS(in DOMString namespaceURI, in DOMString qualifiedName);
  NodeList getElementsByTagNameNS(in DOMString namespaceURI, in DOMString localName);
  Element getElementById(in DOMString elementId);
  readonly attribute DOMString inputEncoding;
           attribute DOMString documentURI;
  Node adoptNode(in Node source);
};

The doctype attribute must return the first child of the Document node that is a DocumentType node, if there is one, or null otherwise.

The implementation attribute must return the DOMImplementation object that is associated with the Document node.

The documentElement attribute must return the first child of the Document node that is an Element node, if there is one, or null otherwise.

The createElement(tagName) method must run the following steps:

  1. If tagName doesn't match the Name production in XML, raise an INVALID_CHARACTER_ERR exception and abort these steps. [XML]

  2. Return a new Element node with no attributes, namespaceURI set to "http://www.w3.org/1999/xhtml", prefix set to null, localName set to tagName, converted to lowercase, and ownerDocument set to the context node.

No check is performed that the local name will match the NCName production in Namespaces in XML. [XMLNS]

The createDocumentFragment() method must return a new DocumentFragment node with its ownerDocument set to the context node.

The createTextNode(data) method must return a new Text node with its data attribute set to data and ownerDocument set to the context node.

No check is performed that the text node contains characters that match the Char production in XML. [XML]

The createComment(data) method must return a new Comment node with its data attribute set to data and ownerDocument set to the context node.

No check is performed that the comment contains characters that match the Char production in XML or that it contains two adjacent hyphens or ends with a hyphen. [XML]

The createProcessingInstruction(target, data) method must run the following steps:

  1. If target doesn't match the Name production in XML, raise an INVALID_CHARACTER_ERR exception and abort these steps. [XML]

  2. Return a new ProcessingInstruction node with its target attribute set to target, data attribute set to data and ownerDocument set to the context node.

No check is performed that the processing instruction target contains "xml" or the colon, or that the data contains characters that match the Char production in XML or that it contains the string "?>". [XML]

The getElementsByTagName(localName) method must run the following steps:

  1. If localName is just the character U+002A ASTERISK ("*"), return a NodeList rooted at the context node, whose filter matches only Element nodes.

  2. Otherwise, return a NodeList rooted at the context node, whose filter matches only Element nodes that have a localName equal to localName.

The importNode(importedNode, deep) method must return a clone of importedNode, with new ownerDocument being the context node, and the clone children flag set if deep is true.

The createElementNS(namespaceURI, qualifiedName) method must run the following steps:

  1. If qualifiedName doesn't match the Name production in XML, raise an INVALID_CHARACTER_ERR exception and abort these steps. [XML]

  2. If qualifiedName doesn't match the QName production in Namespaces in XML, raise an NAMESPACE_ERR exception and abort these steps. [XMLNS]

  3. If qualifiedName contains a U+003E COLON (":") character, then split the string on the colon and let prefix be the part before the colon and localName the part after the colon. Otherwise, let prefix be null and localName be qualifiedName.

  4. Return a new Element node with no attributes, namespaceURI set to namespaceURI, prefix set to prefix, localName set to localName, and ownerDocument set to the context node.

The getElementsByTagNameNS(namespaceURI, localName) method must run the following steps:

  1. If both namespaceURI and localName are just the character U+002A ASTERISK ("*"), return a NodeList rooted at the context node, whose filter matches only Element nodes.

  2. Otherwise, if namespaceURI is just the character U+002A ASTERISK ("*"), return a NodeList rooted at the context node, whose filter matches only Element nodes with the localName equal to localName.

  3. Otherwise, if localName is just the character U+002A ASTERISK ("*"), return a NodeList rooted at the context node, whose filter matches only Element nodes with the namespaceURI equal to namespaceURI.

  4. Otherwise, return a NodeList rooted at the context node, whose filter matches only Element nodes that have a namespaceURI equal to namespaceURI and a localName equal to localName (both in a case-sensitive manner).

The getElementById(elementId) method must return the first Element node, in tree order, in the context node that has the ID elementId, or null if there is none.

The adoptNode(source) method must run the following steps:

  1. If source's parentNode is not null, remove source from its parent.

  2. Set source's ownerDocument to the context node.

  3. Return source.

Interface Node

interface Node {

  // NodeType
  const unsigned short ELEMENT_NODE = 1;
  const unsigned short ATTRIBUTE_NODE = 2;
  const unsigned short TEXT_NODE = 3;
  const unsigned short CDATA_SECTION_NODE = 4; // historical
  const unsigned short ENTITY_REFERENCE_NODE = 5; // historical
  const unsigned short ENTITY_NODE = 6; // historical
  const unsigned short PROCESSING_INSTRUCTION_NODE = 7;
  const unsigned short COMMENT_NODE = 8;
  const unsigned short DOCUMENT_NODE = 9;
  const unsigned short DOCUMENT_TYPE_NODE = 10;
  const unsigned short DOCUMENT_FRAGMENT_NODE = 11;
  const unsigned short NOTATION_NODE = 12; // historical

  readonly attribute DOMString nodeName;
           attribute DOMString nodeValue;
  readonly attribute unsigned short nodeType;
  readonly attribute Node parentNode;
  readonly attribute Element parentElement;
  readonly attribute NodeList childNodes;
  readonly attribute Node firstChild;
  readonly attribute Node lastChild;
  readonly attribute Node previousSibling;
  readonly attribute Node nextSibling;
  readonly attribute NamedNodeMap attributes;
  readonly attribute Document ownerDocument;
  Node insertBefore(in Node newChild, [Undefined=Null] in Node refChild);
  Node replaceChild(in Node newChild, in Node oldChild);
  Node removeChild(in Node oldChild);
  Node appendChild(in Node newChild);
  boolean hasChildNodes();
  Node cloneNode(in boolean deep);
  boolean isSupported(in DOMString feature, in DOMString version);
  readonly attribute DOMString namespaceURI;
  readonly attribute DOMString prefix;
  readonly attribute DOMString localName;
  boolean hasAttributes();
  readonly attribute DOMString baseURI;

  // DocumentPosition
  const unsigned short DOCUMENT_POSITION_DISCONNECTED = 0x01;
  const unsigned short DOCUMENT_POSITION_PRECEDING = 0x02;
  const unsigned short DOCUMENT_POSITION_FOLLOWING = 0x04;
  const unsigned short DOCUMENT_POSITION_CONTAINS = 0x08;
  const unsigned short DOCUMENT_POSITION_CONTAINED_BY = 0x10;
  const unsigned short DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC = 0x20;

  unsigned short compareDocumentPosition(in Node other);

  [Null=Empty] attribute DOMString textContent;
  boolean isSameNode(in Node other);
  DOMString lookupPrefix(in DOMString namespaceURI);
  boolean isDefaultNamespace(in DOMString namespaceURI);
  DOMString lookupNamespaceURI(in DOMString prefix);
  boolean isEqualNode(in Node arg);
};

The nodeName, nodeValue and nodeType attributes must, on getting, return what is in the second, third and forth column, respectively, if the node also implements the interface in the first column on the same row in the following table:

InterfacenodeNamenodeValuenodeType
Elementsame as tagNamenull1
Attrsame as namesame as value2
Text"#text"same as data3
ProcessingInstructionsame as targetsame as data7
Comment"#comment"same as data8
Document"#document"null9
DocumentTypesame as namenull10
DocumentFragment"#document-fragment"null11

The parentNode attribute must, on getting, return the parent node of the context node, or null if there is no parent.

The parentElement attribute must, on getting, return the parent node of the context node if there is a parent and it is an element, or null otherwise.

The childNodes attribute must, on getting, return a NodeList rooted at the context node matching only child nodes.

The firstChild attribute must, on getting, return the first child node of the context node, or null if there is none.

The lastChild attribute must, on getting, return the last child node of the context node, or null if there is none.

The previousSibling attribute must, on getting, return the previous sibling node of the context node, or null if there is none.

The nextSibling attribute must, on getting, return the next sibling node of the context node, or null if there is none.

The attributes attribute must, on getting, return a NamedNodeMap of all the Attr nodes associated with the node of the context node, if it is an Element node, or null otherwise.

The ownerDocument attribute must, on getting, return the Document node that the context node is associated with, or null if there is none.

The insertBefore(newChild, refChild) method must run the following steps:

  1. If newChild doesn't implement the Node interface, or if refChild is not null or doesn't implement the Node interface, then raise a NOT_SUPPORTED_ERR exception and abort these steps.

  2. If refChild is not null and is not a child of the context node, then raise a NOT_FOUND_ERR exception and abort these steps.

  3. If newChild is a DocumentFragment node, then while newChild's firstChild is not null, call insertBefore on the context node with newChild's firstChild as first argument and refChild as second argument.

  4. Otherwise, if refChild is null, append newChild to the context node.

  5. Otherwise insert newChild in the context node as the previous sibling of refChild.

  6. Return newChild.

The replaceChild(newChild, oldChild) method must run the following steps:

  1. If newChild or oldChild doesn't implement the Node interface, then raise a NOT_SUPPORTED_ERR exception and abort these steps.

  2. If oldChild is not a child of the context node, then raise a NOT_FOUND_ERR exception and abort these steps.

  3. Let refChild be oldChild's nextSibling.

  4. Remove oldChild from context node.

  5. Call insertBefore on the context node with newChild and refChild as arguments, respectively.

  6. Return newChild.

The removeChild(oldChild) method must run the following steps:

  1. If oldChild doesn't implement the Node interface, then raise a NOT_SUPPORTED_ERR exception and abort these steps.

  2. If oldChild is not a child of the context node, then raise a NOT_FOUND_ERR exception and abort these steps.

  3. Remove oldChild from context node.

  4. Return oldChild.

The appendChild(newChild) method must run the following steps:

  1. If newChild doesn't implement the Node interface, then raise a NOT_SUPPORTED_ERR exception and abort these steps.

  2. Append newChild to the context node.

  3. Return newChild.

The hasChildNodes() method must return false if the context node's firstChild is null, and true otherwise.

The cloneNode(deep) method must return a clone of the context node, with new ownerDocument being the context node's ownerDocument, and the clone children flag set if deep is true.

The isSupported(feature, version) method must return true if the UA supports the given feature feature of version version on the context node, and false otherwise.

The namespaceURI attribute, on getting, must return the namespace that is associated with the node, if there is one and it's not the empty string, or null otherwise.

The prefix attribute, on getting, must return the prefix that is associated with the node, if there is one and it's not the empty string, or null otherwise.

The localName attribute, on getting, must return the local name that is associated with the node.

The hasAttributes() method must ...

The baseURI attribute must ...

The compareDocumentPosition(other) method must ...

The textContent attribute, on getting, must return a concatenation of the data of all the descendant Text nodes of the context node, in tree order. On setting, it must run the following steps:

  1. Remove all the child nodes of the context node.

  2. Let data be the value being assigned.

  3. If data is not the empty string, append a new Text node to the context node whose data is set to data.

The isSameNode(other) method must return true if other is a reference to the same object as the context node, and false otherwise.

The lookupPrefix(namespaceURI) method must ...

The isDefaultNamespace(namespaceURI) method must ...

The lookupNamespaceURI(prefix) method must ...

The isEqualNode(arg) method must return true if all of the following conditions are true, and must otherwise return false:

Interface NodeList

A NodeList is a collection, except that NodeLists can be static (as opposed to live) if a specification defines them to be static. [HTML5]

interface NodeList {
  [IndexGetter] Node item(in unsigned long index);
  readonly attribute unsigned long length;
};

The item(index) method must return the indexth node in the collection. If there is no indexth node in the collection, then the method must return null.

The length attribute must, on getting, return the number of nodes represented by the collection.

Interface NamedNodeMap

interface NamedNodeMap {
  Node getNamedItem(in DOMString name);
  Node setNamedItem(in Node arg);
  Node removeNamedItem(in DOMString name);
  Node item(in unsigned long index);
  readonly attribute unsigned long length;
  Node getNamedItemNS(in DOMString namespaceURI, in DOMString localName);
  Node setNamedItemNS(in Node arg);
  Node removeNamedItemNS(in DOMString namespaceURI, in DOMString localName);
};

Interface CharacterData

interface CharacterData : Node {
  [Null=Empty] attribute DOMString data;
  readonly attribute unsigned long length;
  DOMString substringData(in unsigned long offset, in unsigned long count);
  void appendData(in DOMString arg);
  void insertData(in unsigned long offset, in DOMString arg);
  void deleteData(in unsigned long offset, in unsigned long count);
  void replaceData(in unsigned long offset, in unsigned long count, in DOMString arg);
};

The data attribute must, on getting, return the data of the node, and on setting, must change the node's data to the new value.

The length attribute must, on getting, return the number of UTF-16 code units represented by the node's data.

The substringData(offset, count) method must run the following steps:

  1. If offset is negative or is greater than the context node's length, or if count is negative, raise an INDEX_SIZE_ERR exception and abort these steps.

  2. If offset+count is greater than the context node's length, return a DOMString whose value is the UTF-16 code units from the offsetth UTF-16 code unit to the end of data.

  3. Return a DOMString whose value is the UTF-16 code units from the offsetth UTF-16 code unit to the offset+countth UTF-16 code unit in data.

Interface Attr

interface Attr : Node {
  readonly attribute DOMString name;
  readonly attribute boolean specified;
           attribute DOMString value;
  readonly attribute Element ownerElement;
};

Interface Element

interface Element : Node {
  readonly attribute DOMString tagName;
  DOMString getAttribute(in DOMString name);
  void setAttribute(in DOMString name, in DOMString value);
  void removeAttribute(in DOMString name);
  NodeList getElementsByTagName(in DOMString name);
  DOMString getAttributeNS(in DOMString namespaceURI, in DOMString localName);
  void setAttributeNS(in DOMString namespaceURI, in DOMString qualifiedName, in DOMString value);
  void removeAttributeNS(in DOMString namespaceURI, in DOMString localName);
  NodeList getElementsByTagNameNS(in DOMString namespaceURI, in DOMString localName);
  boolean hasAttribute(in DOMString name);
  boolean hasAttributeNS(in DOMString namespaceURI, in DOMString localName);
           attribute HTMLCollection children;
};

HTMLCollection is defined in HTML5. Perhaps we should move that to this spec. Perhaps also DOMTokenList, DOMStringMap, getElementsByClassName...

The tagName attribute must, on getting, return the concatenation of prefix, the character U+003E COLON (":") and localName if prefix is not null, and otherwise just localName.

Interface Text

interface Text : CharacterData {
  Text splitText(in unsigned long offset);
  readonly attribute DOMString wholeText;
  Text replaceWholeText(in DOMString content);
};

Interface Comment

interface Comment : CharacterData {
};

Interface DocumentType

interface DocumentType : Node {
  readonly attribute DOMString name;
  readonly attribute DOMString publicId;
  readonly attribute DOMString systemId;
};

Interface ProcessingInstruction

interface ProcessingInstruction : Node {
  readonly attribute DOMString target;
           attribute DOMString data;
};

Acknowledgements

Thanks to Anne van Kesteren and Henri Sivonen for their useful comments.