AbstractThe Document Object Model (DOM) level one provides a mechanism for software developers and web script authors to access and manipulate parsed HTML and XML content. All markup as well as any document type declarations are made available. Level one also allows creation "from scratch" of entire web documents in memory; saving those documents persistently is left to the programmer. DOM Level one is intentionally limited in scope to content representation and manipulation; rendering, validation, externalization etc. are deferred to higher levels of the DOM. |
This document is part of the Document Object Model Specification
This specification defines a minimal set of objects and interfaces for accessing and manipulating document objects. The functionality specified in this draft (the "core" functionality) should be sufficient to implement higher level operations, such as querying, and filtering of a document; future drafts will add "utility" operations which can be implemented in terms of the core operations, but which may be implemented more efficiently using implementation-specific mechanisms that fall outside of the scope of this specification.
The audience for this document is intended to be web script authors, software developers, and DOM implementation providers. This document presumes familiarity with concepts and terminology from HTML and XML, as well as object oriented programming. The actual DOM specification is provided in the Object Management Group's Interface Definition Language (IDL); experience with Java or C++ syntax should be sufficient to allow comprehension.
The DOM objects and interfaces are designed to be:
Note: In the current specification, some operations can modify the document tree, but there is no model for handling concurrent access. The WG also recognises that in some situations, a document, or some of its components, will not be modifiable, and a method for dealing with such situations needs to be defined.
The Document Object Model defines a representation of a hierarchy of objects (i.e. a tree, or "structure model"), called "nodes". The object hierarchy is typically created from a source representation such as HTML or XML via some implementation-specific mechanism that falls outside the scope of this specification.
Node | +--Document | +--Element | +--Attribute | +--Text | +--Comment | +--PI
These types are "helpers" which can appear in various parts of the DOM. Some of them occur quite frequently in common usage; others are limited to the Document Type Definition section of the document, and thus may be of little interest to typical DOM users. Those types are marked accordingly.
In the DOM core, there are no objects representing entities. Numeric character references and references to the pre-defined entities in HTML and XML, are replaced by the single character that makes up the entities replacement. For example, in:
<p>This is a dog & a cat</p>
the "&" will be replaced by the character "&", and the text in the <p> element will form a single continuous sequence of characters. The representation of general entities, both internal and external, are defined within the XML-specific portion of the level one specification.
Note: When a DOM representation of a document is converted to its textual form as XML or HTML, applications will need to check each character in text data to see if it needs to be escaped using a numeric or pre-defined entity. Failing to do so could result in invalid HTML or XML.
The primary Document Object Model type definitions are presented using the Object Management Group's Interface Definition Language (IDL, ISO standard 14750). While a complete tutorial on the IDL language is beyond the scope of this document, a few key items deserve explicit mentioning:
long
datatype represents 32 signed bit integers.
In other language bindings, for example Java, this would be mapped to
the Java int
datatype. More information on IDL is available from OMG and in chapter 3 of the CORBA 2.0 specification.
Note: The Object Management Group Interface Definition Language (OMG IDL) was chosen as it was designed for specifying language and implementation-neutral interfaces. Various other IDLs could be used; the use of OMG IDL does not imply a requirement to use a specific object binding runtime.
The types described in this section are those that application programmers using the DOM will encounter most frequently. A good working knowledge of these types will be sufficient to accomplish most tasks.
Node is the base type of most objects in the Document Object Model. It may have an arbitrary number (including zero) of sequentially ordered child nodes. It usually has a parent Node; the exception being that the root Node in a document hierarchy has no parent.
Element objects represent the elements in the HTML or XML document. Elements contain, as child nodes, all the content between the start tag, and the end tag of an element. Additionally, Element objects have a list of Attribute objects which represent the combination of those attributes explicitly specified in the document, and those defined in the document type definition which have default values.
The Document object represents the root node of
a document. It typically1 has
no parent; the getParentNode()
method will return null
.
Normally, a DOM-compliant implementation will make the main Document instance available to the application2 through some implementation-specific mechanism. For example, a typical implementation would pass the application a reference to a DocumentContext object. From the DocumentContext, the application may retrieve the Document object, which is the root of the document object hierarchy.
Once the application has access to the root of the document object hierarchy, it can use the methods defined herein for accessing individual nodes, selection of specific node types such as all images, and so on.
This section defines the complete set of objects and methods which are defined by the Document Object Model. The general structure of these object definitions is:
The Document object represents the entire HTML or XML document. Conceptually, it is the root of the document tree, and provides the primary access to the document's data.
Node documentType
null
. Element documentElement
"HTML"
;
for XML this is the outermost element, i.e. the element
non-terminal in production [41] in
Section 3 of the
XML-lang specification. NodeEnumerator getElementsByTagName(wstring name)
tagName
matches the given name. The iteration order is a depth first
enumeration of the elements as they occurred in the original document.
Note: a future version of the DOM will provide a more generalized querying mechanism for Nodes. One such query involves obtaining all the Elements in a subtree with a given tagName. A convenience method for this query has been included in the core document. This method might be removed at a later date in favor of a more comprehensive querying mechanism.
The "DOM" interface provides a number of methods for performing operations that are independent of any particular instance of the document object model. The only operations currently supported is to retrieve the factory object. It is expected, however, that other operations such as querying for the version number of a particular DOM implementation, or asking about the versions of HTML or XML supported by a particular DOM implementation would also be present on this interface. Although IDL does not provide a mechanism for expressing the concept, the methods supplied by the DOM interface will be implemented as "static", or instance independent, methods. This means that a client application using the DOM does not have to locate a specific instance of the DOM object; rather, the methods are will be available directly on the DOM class itself and so are directly accessible from any execution context.
DOMFactory getFactory()
Note that in the future it is expected that there will be additional static methods on the DOM itself to allow for specification of which factory object to be returned.
The methods on the DOMFactory interface allow DOM clients to create new DOM objects. An application developer who needed to create an entire document object model programmatically would use the methods on a DOMFactory object to build the individual objects that comprise the object model, and use the operations on the objects themselves to connect the objects into an overall document object model.
Document createDocument()
DocumentContext createDocumentContext()
Element createElement(in wstring tagName, in AttributeList
attributes)
Text createTextNode(in wstring data)
Comment createComment(in wstring data)
PI createPI(in wstring name, in wstring data)
Attribute createAttribute(in wstring name, in NodeList value)
The DocumentContext object represents information that is not strictly related to a document's content; rather, it provides the information about where the document came from, and any additional meta-data about the document. For example, the DocumentContext for a document retrieved using HTTP would provide access to the HTTP headers which were retrieved with the document, the URL that the document came from, etc.
For documents which were not retrieved via HTTP, or for those which were created directly in memory, there may be no DocumentContext.
NOTE: The DocumentContext interface described here is expected to be significantly expanded in the level two specification of the Document Object Model.
Document document
The Node object is the primary datatype for the entire Document Object Model. It represents a single node in the document tree. Nodes may have, but are not required to have, an arbitrary number of child nodes.
NodeType getNodeType()
enum
, and it is expected that most
language bindings will represent this runtime-queryable Node type using
an integral data type. The names of the node type enumeration literals
are straightforwardly derived from the names of the actual Node
subtypes, and are fully specified in the IDL definition of Node in the
IDL definition in Appendix A. Node getParentNode()
null
is returned. [Note:
because in ECMAScript get/set method pairs are surfaced as properties,
Parent would conflict with the pre-defined Parent property, so we
disambiguate this with "ParentNode" even though it is
inconsistent with the naming convention of the other methods that do not
include "Node"]. NodeList getChildren()
null
is returned. The content of
the returned NodeList is "live" in the sense that changes to
the children of the Node object that it was created from will be
immediately reflected in the set of Nodes the NodeList contains; it is
not a static snapshot of the content of the Node. Similarly, changes
made to the NodeList will be immediately reflected in the set of
children of the Node that the NodeList was created from. boolean hasChildren()
true
if the node has any children, false
if the node has no children at all. This method exists both for
convenience as well as to allow implementations to be able to bypass
object allocation, which may be required for implementing getChildren()
.
Node getFirstChild()
null
is returned. Node getPreviousSibling()
null
is returned. Node getNextSibling()
null
is returned. Node insertBefore(in Node newChild, in Node refChild) raises
(NotMyChildException)
null
,
insert newChild at the end of the list of children. If
refChild is not a child of the Node that insertBefore
is being invoked on, a NotMyChildException
is thrown.
Node replaceChild(in Node oldChild, in Node newChild) raises
(NotMyChildException)
replaceChild
method is being invoked on, a NotMyChildException
is thrown. Node removeChild(in Node oldChild) raises
(NotMyChildException)
NotMyChildException
is thrown. The NodeList object provides the abstraction of an immutable ordered collection of Nodes, without defining or constraining how this collection is implemented, allowing different DOM implementations to be tuned for their specific environments.
The items in the NodeList are accessible via an integral index, starting from 0. A NodeEnumerator object may be created to allow simple sequential traversal over the members of the list.
NodeEnumerator getEnumerator()
Node item(in unsigned long index) raises(NoSuchNodeException)
NoSuchNodeException
is thrown. unsigned long getLength()
getLength()-1
inclusive.
EditableNodeList is a subtype of NodeList that adds operations that modify the list of nodes, such as adding, deleting and replacing Node instances in the list.
Node replace(in unsigned long index, in Node replacedNode)
raises (NoSuchNodeException)
null
is
returned if the index is equal to the previous number of nodes in the
list). If index is greater than the number of nodes in the
list, a NoSuchNodeException
is thrown. void insert(in unsigned long index, in Node newNode) raises
(NoSuchNodeException)
self.getLength()
, the node is added at the end of the
list. Node remove(in unsigned long index) raises
(NoSuchNodeException)
NoSuchNodeException
is thrown. This class provides a generic iteration mechanism over an arbitrary collection of nodes. The nodes may be enumerated in either forward or reverse order, and the direction of enumeration may be changed at any time. The enumerator behaves as though it had an internal "pointer" to the current node, and provides methods for abstractly changing the notion of what the current node is.
Typical usage (in some C++ like language) might look like:
NodeEnumerator nodeEnum = document.getChildren().getEnumerator(); for (Node node = nodeEnum.first(); node != null; node = nodeEnum.next()) { // ... do some computation on that node }
Node getFirst()
null
is returned.
NOTE: in some implementations this may or may not be a fast operation; it may be the case that the enumeration finds the requested node on demand, and for very large document object, this may take some time.
Node getNext()
null
after the last node in the list
has been passed, and leaves the current pointer at the last node. Node getPrevious()
null
after the first node in the
enumeration has been returned, and leaves the current pointer at the
first node. Node getLast()
null
. Doing a getNext()
immediately after this operation will return null
. Node getCurrent()
null
if the enumeration is empty. boolean atStart()
getCurrent()
will return the same node as getFirst()
would return. For
empty enumerations, true is always returned. Does not affect the state
of the enumeration in any way. boolean atEnd()
getCurrent()
will
return the same node as getLast()
would return. For empty
enumerations, true is always returned. Does not affect the state of the
enumeration in any way. AttributeList objects are used to represent collections of Attribute objects which can be accessed by name. The Attribute objects contained in a AttributeList may also be accessed by ordinal index. In most cases, AttributeList objects are created from Element objects.
Attribute getAttribute(in wstring attrName)
null
is returned. Attribute setAttribute(in wstring attrName, in Attribute attr)
null
is returned, and the named Attribute is added to the end of the
AttributeList object; that is, it is accessible via the item
method using the index one less than the value returned by getLength()
.
Attribute remove(in wstring attrName) raises
(NoSuchAttributeException)
NoSuchAttributeException
is thrown. Attribute item(in unsigned long index)
raises(NoSuchAttributeException)
NoSuchAttributeException
is
thrown. unsigned long getLength()
By far the vast majority (apart from text) of node types that authors will generally encounter when traversing a document will be Element nodes. These objects represent both the element itself, as well as any contained nodes.
For example (in XML):
<elementExample id="demo"> <subelement1/> <subelement2> <subsubelement/> </subelement2> </elementExample>
When represented using DOM, the top node would be "elementExample", which contains two child Element nodes (and some space), one for "subelement1" and one for "subelement2". "subelement1" contains no child nodes of its own.
wstring getTagName()
<elementExample id="demo"> ... </elementExample>This would have the value
"elementExample"
. Note that this is
case-preserving, as are all of the operations of the DOM. See
Name case in the DOM for a description of why the
DOM preserves case.AttributeList attributes
elementExample
example above, the attributes list would consist of the id
attribute, as well as any attributes which were defined by the document
type definition for this element which have default values. void setAttribute(in Attribute newAttr)
NodeEnumerator getElementsByTagName(wstring name)
tagName
matches the given name. The iteration order is a depth first
enumeration of the elements as they occurred in the original document.
Note: a future version of the DOM will provide a more generalized querying mechanism for Nodes. One such query involves obtaining all the Elements in a subtree with a given tagName. A convenience method for this query has been included in the core document. This method might be removed at a later date in favor of a more comprehensive querying mechanism.
The Attribute object represents an attribute in an Element object. Typically the allowable values for the attribute are defined in a document type definition.
wstring getName()
NodeList value
toString()
method will return a zero length string (as will toString()
invoked directly on this Attribute instance). If the attribute has no
effective value, then this method will return null
. Note
the toString()
method on the Attribute instance can also
be used to retrieve the string version of the attribute's value(s).
boolean specified
wstring toString()
Represents the content of a comment, i.e. all the characters between the
starting '<!--
' and ending '-->
'. Note
that this is the definition of a comment in XML, and, in practice, HTML,
although some HTML tools may implement the full SGML comment structure.
wstring data
A PI node is a "processing instruction". The content of the PI node is the entire content between the delimiters of the processing instruction
wstring name
null
. wstring data
<?
(after the name in XML) to the
character immediately preceding the ?>
. The Text object contains the non-markup portion of a document. For XML documents, all whitespace between markup results in Text nodes being created.
wstring data
boolean isIgnorableWhitespace
This document uses the the term "application" to mean the set of code that is using the DOM to inspect and manipulate the document object; for example scripts and/or full-scale applications.
Sometimes it may make sense to have a document node be stored as child of another node. For example, at some point during the creation of a document that's representing XML links, it may be valuable to be able to have the target document(s) directly accessible in the node hierarchy.
Parsed XML includes text nodes for white space between elements, even if there is nothing but whitespace present. The text node contains an indication of whether or not the author of the document intended for the whitespace to be ignored, but, according to the XML specification, white space must be passed to the DOM verbatim.
The Document Object Model does not change the case of any identifiers present in a parsed document. XML preserves the case of identifiers (and indeed recognizes upper and lower case versions of the same identifier as distinct), and the HTML specification says that markup is handled case-insensitively, and many implementations of HTML tools interpret this to mean that element and attribute names are lowercased. So, in order to not lose case information, the methods in the Document Object Model do not alter the case of returned identifiers.
Application developers using the DOM for HTML would be wise to use case-insensitive comparisons when testing for equality.
This section contains the IDL definitions for the objects in the core Document Object Model. The HTML IDL definition is here, and the XML IDL definition, including the types to represent the document type definition is here.
//hb////-*-Mode: C++-*-//////////////////////////////////////////////////////// // // // NAME : // // DESCRIPTION : // // HISTORY : // // // //he/////////////////////////////////////////////////////////////////////////// exception NoSuchNodeException { }; exception NotMyChildException { }; // Enumerator class for a node list interface NodeEnumerator { Node getFirst(); Node getNext(); Node getPrevious(); Node getLast(); Node getCurrent(); // The rationale for their existence is that the enumerator may be used // internally to a method, which may return some interesting value, and // therefore cannot also indicate whether the start or end of enumeration // was reached. Any of the traversal methods affects the state, and // so are not suitable for usage as predicates (unless possible state // manipulation is acceptable). boolean atStart(); boolean atEnd(); }; // Define the type for a sequence of nodes interface NodeList { NodeEnumerator getEnumerator(); Node item(in unsigned long index) raises(NoSuchNodeException); // This may be expensive to compute unsigned long getLength(); }; // Define the type for a sequence of nodes interface EditableNodeList : NodeList { void replace(in unsigned long index, in Node replacedNode) raises (NoSuchNodeException); void insert(in unsigned long index, in Node newNode) raises (NoSuchNodeException); Node remove(in unsigned long index) raises (NoSuchNodeException); }; // Interface to a node in a grove interface Node { enum NodeType { DOCUMENT, ELEMENT, ATTRIBUTE, PI, COMMENT, TEXT }; NodeType getNodeType(); // Simple traversal interface Node getParentNode(); NodeList getChildren(); boolean hasChildren(); Node getFirstChild(); Node getPreviousSibling(); Node getNextSibling(); void insertBefore(in Node newChild, in Node refChild) raises (NotMyChildException); Node replaceChild(in Node oldChild, in Node newChild) raises (NotMyChildException); Node removeChild(in Node oldChild) raises (NotMyChildException); }; // Named node list interface NamedNodeList { // Core get and set interface. Note that implementations may // build the list lazily Node getNode(in wstring name); Node setNode(in wstring name, in Node node); Node remove(in wstring name) raises (NoSuchNodeException); Node item(in unsigned long index) raises(NoSuchNodeException); unsigned long getLength(); NodeEnumerator getEnumerator(); }; ////////////////////////////////////////////////////////////////////////// // // // OBJECTS RELATED TO THE DOM ITSELF // // // ////////////////////////////////////////////////////////////////////////// interface DOM { DOMFactory getFactory(); }; interface DOMFactory { Document createDocument(); DocumentContext createDocumentContext(); Element createElement(in wstring tagName, in AttributeList attributes); Text createTextNode(in wstring data); Comment createComment(in wstring data); PI createPI(in wstring name, in wstring data); Attribute createAttribute(in wstring name, in NodeList value); }; interface DocumentContext { attribute Document document; }; interface Document : Node { attribute Node documentType; attribute Element documentElement; NodeEnumerator getElementsByTagName(in wstring name); }; ////////////////////////////////////////////////////////////////////////// // // // OBJECTS RELATED TO THE INSTANCE // // // ////////////////////////////////////////////////////////////////////////// interface Attribute : Node { // attribute wstring name; attribute NodeList value; attribute boolean specified; // provides a connection to the DTD // attribute Node definition; wstring toString(); }; // Attribute list interface AttributeList { Attribute getAttribute(in wstring name); Attribute setAttribute(in wstring name, in Attribute attr); Attribute remove(in wstring name) raises (NoSuchNodeException); Node item(in unsigned long index) raises(NoSuchNodeException); unsigned long getLength(); }; // Processing Instruction interface PI : Node { attribute wstring name; attribute wstring data; }; interface Element : Node { // attribute wstring tagName; attribute AttributeList attributes; void setAttribute(in Attribute newAttr); NodeEnumerator getElementsByTagName(in wstring name); }; // Represents the content of <!-- ... --> interface Comment : Node { attribute wstring data; }; interface Text : Node { attribute wstring data; attribute boolean isIgnorableWhitespace; };
// Nodes, node lists, and enumerators for node lists public class NoSuchNodeException extends Exception { }; public class NotMyChildException extends Exception { }; // NodeEnumerator traverses the nodes in a NodeList. public interface NodeEnumerator { Node getFirst(); Node getNext(); Node getPrevious(); Node getLast(); Node getCurrent(); // The rationale for their existence is that the enumerator may be used // internally to a method, which may return some interesting value, and // therefore cannot also indicate whether the start or end of enumeration // was reached. Any of the traversal methods affects the state, and // so are not suitable for usage as predicates (unless possible state // manipulation is acceptable). boolean atStart(); boolean atEnd(); }; public interface NodeList { NodeEnumerator getEnumerator(); Node item(long index) throws NoSuchNodeException; long getLength(); }; public interface EditableNodeList extends NodeList { void replace(long index,Node replacedNode) throws NoSuchNodeException; void insert(long index,Node newNode) throws NoSuchNodeException; Node remove(long index) throws NoSuchNodeException; }; public interface Node { public final class NodeType { public final int DOCUMENT = 0; public final int ELEMENT = 1; public final int ATTRIBUTE = 2; public final int PI = 3; public final int COMMENT = 4; public final int TEXT = 5; }; // getNodeType() returns one of the NodeType constants // defined above. int getNodeType(); Node getParentNode(); NodeList getChildren(); boolean hasChildren(); Node getFirstChild(); Node getPreviousSibling(); Node getNextSibling(); void insertBefore(Node newChild, Node refChild) throws NotMyChildException; Node replaceChild(Node oldChild, Node newChild) throws NotMyChildException; Node removeChild(Node oldChild) throws NotMyChildException; }; public interface NamedNodeList { // Core get and set public interface. Note that implementations may // build the list lazily Node getNode(String name); Node setNode(String name, Node node); Node remove(String name) throws NoSuchNodeException; Node item(long index) throws NoSuchNodeException; long getLength(); NodeEnumerator getEnumerator(); }; public interface DOM { DOMFactory getFactory(); }; public interface DOMFactory { Document createDocument(); DocumentContext createDocumentContext(); Element createElement(String tagName, AttributeList attributes); Text createTextNode(String data); Comment createComment(String data); PI createPI(String name, String data); Attribute createAttribute(String name, NodeList value); }; public interface DocumentContext { void setDocument(Document document); Document getDocument(); }; public interface Document extends Node { void setDocumentType(Node documentType); Node getDocumentType(); void setDocumentElement(Element documentElement); Element getDocumentElement(); NodeEnumerator getElementsByTagName(String name); }; public interface Attribute extends Node { void setName(String name); String getName(); void setValue(NodeList value); NodeList getValue(); void setSpecified(boolean specified); boolean getSpecified(); // provides a connection to the DTD // attribute Node definition; String toString(); }; public interface AttributeList { Attribute getAttribute(String name); Attribute setAttribute(String name, Attribute attr); Attribute remove(String name) throws NoSuchNodeException; Node item(long index) throws NoSuchNodeException; long getLength(); }; // Processing Instruction public interface PI extends Node { void setName(String name); String getName(); void setData(String data); String getData(); }; public interface Element extends Node { void setTagName(String tagName); String getTagName(); void setAttributes(AttributeList attributes); AttributeList getAttributes(); void setAttribute(Attribute newAttr); NodeEnumerator getElementsByTagName(String name); }; // Represents the content of <!-- ... --> public interface Comment extends Node { void setData(String data); String getData(); }; public interface Text extends Node { void setData(String data); String getData(); void setIsIgnorableWhitespace(boolean isIgnorableWhitespace); boolean getIsIgnorableWhitespace(); };
Note: This section will contain the complete DOM core bindings for ECMAScript when they become available. We expect this to occur in the very near future as the level one core specification reaches maturity.
There are a large number of terms that the DOM uses which may not be familiar to many of the readers. We suggest that you review the glossary if you encounter terms that aren't familiar.