Event: click Class: MouseEvent button: 2
...would result in a 'click' event using the MouseEvent
interface that has button
set to 2
but
screenX
, screenY
, etc, set to 0, false, or null
as appropriate.
If a field does not match any of the attributes on the event, it must be ignored.
For example:
Event: keypress Class: MouseEvent keyIdentifier: 0
...would result in a MouseEvent
event with its fields all
at their default values, with the event name being keypress
. The keyIdentifier
field
would be ignored. (If the author had not included the Class
field explicitly, it would have just worked, since
the class would have defaulted as described above.)
Once a blank line or the end of the file is reached, an event of the
type and namespace given by the Event
and
Namespace
fields respectively must be synthesized and
dispatched to the appropriate node as described by the fields above. No
event must be dispatched until a blank line has been received or the end
of the file reached.
The event must be dispatched as if using the DOM dispatchEvent()
method. Thus, if the Event
field was omitted, leaving the name as the empty
string, or if the name had invalid characters, then the dispatching of the
event fails.
Events fired from event sources do not have user-agent default actions.
The following event stream, once followed by a blank line:
data: YHOO data: -2 data: 10
...would cause an event message
with the interface MessageEvent
to be dispatched on the
event-source
element, which
would then bubble up the DOM, and whose data
attribute
would contain the string YHOO\n-2\n10
(where \n
again represents a newline).
This could be used as follows:
<event-source src="http://stocks.example.com/ticker.php" onmessage="var data = event.data.split('\n'); updateStocks(data[0], data[1], data[2]);">
...where updateStocks()
is a function defined as:
function updateStocks(symbol, delta, value) { ... }
...or some such.
The following stream contains four blocks and therefore fires four
events. The first block has just a comment, and will fire a message
event with all
the fields set to the empty string or null. The second block has two
fields with names "load" and "Target" respectively; since there is no
"load
" member on the MessageEvent
object that field is
ignored, leaving the event as a second message
event with all the fields set to the
empty string or null, but this time the event is targetted at an element
with ID "image1". The third block is empty (no lines between two blank
lines), and the fourth block has only two comments, so they both yet
again fire message
events with all the fields set to the
empty string or null.
; test load Target: #image1 ; if any more events follow this block, they will not be affected by ; the "Target" and "load" fields above.
Legacy proxy servers are known to, in certain cases, drop HTTP connections after a short timeout. To protect against such proxy servers, authors can include a comment line (one starting with a ';' character) every 15 seconds or so.
Authors wishing to relate event source connections to each other or to
specific documents previously served might find that relying on IP
addresses doesn't work, as individual clients can have multiple IP
addresses (due to having multiple proxy servers) and individual IP
addresses can have multiple clients (due to sharing a proxy server). It is
better to include a unique identifier in the document when it is served
and then pass that identifier as part of the URI in the src
attribute of
the event-source
element.
Implementations that support HTTP's per-server connection limitation
might run into trouble when opening multiple pages from a site if each
page has an event-source
to the
same domain. Authors can avoid this using the relatively complex mechanism
of using unique domain names per connection, or by allowing the user to
enable or disable the event-source
functionality on a per-page
basis.
To enable Web applications to communicate with each other in local area
networks, and to maintain bidirectional communications with their
originating server, this specification introduces the Connection
interface.
The Window
interface provides three
constructors for creating Connection
objects: TCPConnection()
, for creating a direct
(possibly encrypted) link to another node on the Internet using TCP/IP;
LocalBroadcastConnection()
,
for creating a connection to any listening peer on a local network (which
could be a local TCP/IP subnet using UDP, a Bluetooth PAN, or another kind
of network infrastructure); and PeerToPeerConnection()
, for a
direct peer-to-peer connection (which could again be over TCP/IP,
Bluetooth, IrDA, or some other type of network).
This interface does not allow for raw access to the underlying network. For example, this interface could not be used to implement an IRC client without proxying messages through a custom server.
This section is non-normative.
An introduction to the client-side and server-side of using the direct connection APIs.
An example of a party-line implementation of a broadcast service, and direct peer-to-peer chat for direct local connections.
Connection
interfaceinterface Connection { readonly attribute DOMString network; readonly attribute DOMString peer; readonly attribute int readyState; attribute EventListener onopen; attribute EventListener onread; attribute EventListener onclose; void send(in DOMString data); void disconnect(); };
Connection
objects must also
implement the EventTarget
interface. [DOM3EVENTS]
When a Connection
object is
created, the UA must try to establish a connection, as described in the
sections below describing each connection type.
The network
attribute
represents the name of the network connection (the value depends on the
kind of connection being established). The peer
attribute identifies the
remote host for direct (non-broadcast) connections.
The network
attribute must be set as soon as the
Connection
object is created, and
keeps the same value for the lifetime of the object. The peer
attribute must
initially be set to the empty string and must be updated once, when the
connection is established, after which point it must keep the same value
for the lifetime of the object.
The readyState
attribute
represents the state of the connection. When the object is created it must
be set to 0. It can have the following values:
Once a connection is established, the readyState
attribute's value must be
changed to 1, and the open
event must be fired on the Connection
object.
When data is received, the read
event will be fired on the Connection
object.
When the connection is closed, the readyState
attribute's value must be
changed to 2, and the close
event must be fired on the Connection
object.
The onopen
, onread
, and onclose
attributes must,
when set, register their new value as an event listener for their
respective events (namely open
, read
, and close
), and unregister their previous value if
any.
The send()
method transmits data using the connection. If the connection is not yet
established, it must raise an INVALID_STATE_ERR
exception. If
the connection is established, then the behaviour depends on the
connection type, as described below.
The disconnect()
method
must close the connection, if it is open. If the connection is already
closed, it must do nothing. Closing the connection causes a close
event to
be fired and the readyState
attribute's value to change, as
described above.
All the events described in this section are events in no namespace, which do not bubble, are not cancelable, and have no default action.
The open
event is fired when the connection is established. UAs must use the normal
Event
interface when firing this event.
The close
event is fired when the connection is closed (whether by the author,
calling the disconnect()
method, or by the server, or by
a network error). UAs must use the normal Event
interface
when firing this event as well.
No information regarding why the connection was closed is passed to the application in this version of this specification.
The read
event is fired when when data is received for a connection. UAs must use
the ConnectionReadEvent
interface for this event.
interface ConnectionReadEvent : Event { readonly attribute DOMString data; readonly attribute DOMString source; void initConnectionReadEvent(in DOMString typeArg, in boolean canBubbleArg, in boolean cancelableArg, in DOMString dataArg); void initConnectionReadEventNS(in DOMString namespaceURI, in DOMString typeArg, in boolean canBubbleArg, in boolean cancelableArg, in DOMString dataArg); };
The initConnectionReadEvent()
and initConnectionReadEventNS()
methods must initialise the event in a manner analogous to the
similarly-named methods in the DOM3 Events interfaces. [DOM3EVENTS]
The data
attribute
represents the data that was transmitted from the peer.
The source
attribute
represents the name of the peer. This is primarily useful on broadcast
connections; on direct connections it is equal to the peer
attribute on the
Connection
object.
Events that would be fired during script execution (e.g. between the
connection object being created — and thus the connection being
established — and the current script completing; or, during the
execution of a read
event handler) must be buffered, and those
events queued up and each one individually fired after the script has
completed.
The TCPConnection(subdomain,
port, secure)
constructor on the Window
interface
returns a new object implementing the Connection
interface, set up for a direct
connection to a specified host on the page's domain.
When this constructor is invoked, the following steps must be followed.
First, if the domain part of the script's origin is not a host name (e.g. it is an IP address) then the UA must raise a security exception. We currently don't allow connections to be set up back to an originating IP address, but we could, if the subdomain is the empty string.
Then, if the subdomain argument is null or the empty string, the target host is the domain part of the script's origin. Otherwise, the subdomain argument is prepended to the domain part of the script's origin with a dot separating the two strings, and that is the target host.
If either:
...then the UA must raise a security exception.
Otherwise, the user agent must verify that the the string representing the script's domain in IDNA format can be obtained without errors. If it cannot, then the user agent must raise a security exception.
The user agent may also raise a security exception at this time if, for some reason, permission to create a direct TCP connection to the relevant host is denied. Reasons could include the UA being instructed by the user to not allow direct connections, or the UA establishing (for instance using UPnP) that the network topology will cause connections on the specified port to be directed at the wrong host.
If no exceptions are raised by the previous steps, then a new Connection
object must be created, its
peer
attribute
must be set to a string consisting of the name of the target host, a colon
(U+003A COLON), and the port number as decimal digits, and its network
attribute must be set to the same value as the peer
attribute.
This object must then be returned.
The user agent must then begin trying to establish a connection with the target host and specified port. (This typically would begin in the backgound, while the script continues to execute.)
If the secure boolean argument is set to true, then the user agent must establish a secure connection with the target host and specified port using TLS or another protocol, negotiated with the server. [RFC2246] If this fails the user agent must act as if it had closed the connection.
Once a secure connection is established, or if the secure boolean argument is not set to true, then the user agent must continue to connect to the server using the protocol described in the section entitled clients connecting over TCP. All data on connections made using TLS must be sent as "application data".
Once the connection is established, the UA must act as described in the section entitled sending and receiving data over TCP.
User agents should allow multiple TCP connections to be established per
host. In particular, user agents should not apply per-host HTTP connection
limits to connections established with the TCPConnection
constructor.
The LocalBroadcastConnection()
constructor on the Window
interface
returns a new object implementing the Connection
interface, set up to broadcast
on the local network.
When this constructor is invoked, a new Connection
object must be created.
The network
attribute of the object must be set to
the string representing the script's domain in IDNA
format. If this string cannot be obtained, then the user agent must
raise a security exception exception when the
constructor is called.
The peer
attribute must be set to the empty string.
The object must then be returned, unless, for some reason, permission to broadcast on the local network is to be denied. In the latter case, a security exception must be raised instead. User agents may deny such permission for any reason, for example a user preference.
If the object is returned (i.e. if no exception is raised), the user agent must the begin broadcasting and listening on the local network, in the background, as described below. The user agent may define "the local network" in any way it considers appropriate and safe; for instance the user agent may ask the user which network (e.g. Bluetooth, IrDA, Ethernet, etc) the user would like to broadcast on before beginning broadcasting.
UAs may broadcast and listen on multiple networks at once. For example, the UA could broadcast on both Bluetooth and Wifi at the same time.
As soon as the object is returned, the connection has been established, which implies that the
open
event
must be fired. Broadcast connections are never closed.
Should we drop this altogether? Letting people fill the local network with garbage seems unwise.
We need to register a UDP port for this. For now this spec refers to port 18080/udp.
Since this feature requires that the user agent listen to a particular port, some platforms might prevent more than one user agent per IP address from using this feature at any one time.
On TCP/IP networks, broadcast connections transmit data using UDP over port 18080.
When the send(data)
method is invoked on a Connection
object that was created by the
LocalBroadcastConnection()
constructor, the user agent must follow these steps:
network
attribute of the Connection
object, a U+0020 SPACE character, a U+0002 START OF TEXT character, and
the data argument.
INDEX_SIZE_ERR
DOM exception and stop.
When a broadcast connection is opened on a TCP/IP network, the user agent should listen for UDP packets on port 18080.
When the user agent receives a packet on port 18080, the user agent must
attempt to decode that packet's data as UTF-8. If the data is not fully
correct UTF-8 (i.e. if there are decoding errors) then the packet must be
ignored. Otherwise, the user agent must check to see if the decoded string
contains a U+0020 SPACE character. If it does not, then the packet must
again be ignored (it might be a peer discovery packet from a PeerToPeerConnection()
constructor). If it does then the user agent must split the string at the
first space character. All the characters before the space are then known
as d, and all the characters after the space are known
as s. If s is not at least one
character long, or if the first character of s is not
a U+0002 START OF TEXT character, then the packet must be ignored. (This
allows for future extension of this protocol.)
Otherwise, for each Connection
object that was created by the LocalBroadcastConnection()
constructor and whose network
attribute exactly matches d, a read
event must be fired on the Connection
object. The string s, with the first character removed, must be used as the
data
,
and the source IP address of the packet as the source
.
Making the source IP available means that if two or more machines in a private network can be made to go to a hostile page simultaneously, the hostile page can determine the IP addresses used locally (i.e. on the other side of any NAT router). Is there some way we can keep link-local IP addresses secret while still allowing for applications to distinguish between multiple participants?
Does anyone know enough about Bluetooth to write this section?
Does anyone know enough about IrDA to write this section?
The PeerToPeerConnection()
constructor on the Window
interface
returns a new object implementing the Connection
interface, set up for a direct
connection to a user-specified host.
When this constructor is invoked, a new Connection
object must be created.
The network
attribute of the object must be set to
the string representing the script's domain in IDNA
format. If this string cannot be obtained, then the user agent must
raise a security exception exception when the
constructor is called.
The peer
attribute must be set to the empty string.
The object must then be returned, unless, for some reason, permission to establish peer-to-peer connections is generally disallowed, for example due to administrator settings. In the latter case, a security exception must be raised instead.
The user agent must then, typically while the script resumes execution, find a remote host to establish a connection to. To do this it must start broadcasting and listening for peer discovery messages and listening for incoming connection requests on all the supported networks. How this is performed depends on the type of network and is described below.
The UA should inform the user of the clients that are detected, and allow the user to select one to connect to. UAs may also allow users to explicit specify hosts that were not detected, e.g. by having the user enter an IP address.
If an incoming connection is detected before the user specifies a target host, the user agent should ask the user to confirm that this is the host they wish to connect to. If it is, the connection should be accepted and the UA will act as the server in this connection. (Which UA acts as the server and which acts as the client is not discernible at the DOM API level.)
If no incoming connection is detected and if the user specifies a particular target host, a connection should be established to that host, with the UA acting as the client in the connection.
No more than one connection must be established per Connection
object, so once a connection has
been established, the user agent must stop listening for further
connections (unless, or until such time as, another Connection
object is being created).
If at any point the user cancels the connection process or the remote host refuses the connection, then the user agent must act as if it had closed the connection, and stop trying to connect.
Should we replace this section with something that uses Rendez-vous/zeroconf or equivalent?
We need to register ports for this. For now this spec refers to port 18080/udp and 18080/tcp.
Since this feature requires that the user agent listen to a particular port, some platforms might prevent more than one user agent per IP address from using this feature at any one time.
When using TCP/IP, broadcasting peer discovery messages must be done by
creating UDP packets every few seconds containing as their data the value
of the connection's network
attribute, encoded as UTF-8, with the
source and destination ports being set to 18080 and appropriate length and
checksum fields, and sending these packets to address (in IPv4)
<IP_ADDRESS> or (in IPv6) ff02::1, as appropriate.
Listening for peer discovery messages must be done by examining incoming
UDP packets on port 18080. IPv6 applications will also
have to enable reception from the ff02::1 address. If their payload
is exactly byte-for-byte equal to a UTF-8 encoded version of the value of
the connection's network
attribute, then the source address of
that packet represents the address of a host that is ready to accept a
peer-to-peer connection, and it should therefore be offered to the user.
Incoming connection requests must be listened for on TCP port 18080. If an incoming connection is received, the UA must act as a server, as described in the section entitled servers accepting connections over TCP.
If no incoming connection requests are accepted and the user instead specifies a target host to connect to, the UA acts as a client: the user agent must attempt to connect to the user-specified host on port 18080, as described in the section entitled clients connecting over TCP.
Once the connection is established, the UA must act as described in the section entitled sending and receiving data over TCP.
This specification does not include a way to establish secure (encrypted) peer-to-peer connections at this time. If you can see a good way to do this, let me know.
Does anyone know enough about Bluetooth to write this section?
Does anyone know enough about IrDA to write this section?
The same protocol is used for TCPConnection
and PeerToPeerConnection
connection
types. This section describes how such connections are established from
the client and server sides, and then describes how data is sent and
received over such connections (which is the same for both clients and
servers).
This section defines the client-side requirements of the protocol used
by the TCPConnection
and PeerToPeerConnection
connection
types.
If a TCP connection to the specified target host and port cannot be established, for example because the target host is a domain name that cannot be resolved to an IP address, or because packets cannot be routed to the host, the user agent should retry creating the connection. If the user agent gives up trying to connect, the user agent must act as if it had closed the connection.
No information regarding the state of the connection is passed to the application while the connection is being established in this version of this specification.
Once a TCP/IP connection to the remote host is established, the user agent must transmit the following sequence of bytes, represented here in hexadecimal form:
0x48 0x65 0x6C 0x6C 0x6F 0x0A
This represents the string "Hello" followed by a newline, encoded in UTF-8.
The user agent must then read all the bytes sent from the remote host, up to the first 0x0A byte (inclusive). That string of bytes is then compared byte-for-byte to the following string of bytes:
0x57 0x65 0x6C 0x63 0x6F 0x6E 0x65 0x0A
This says "Welcome".
If the server sent back a string in any way different to this, then the user agent must close the connection and give up trying to connect.
Otherwise, the user agent must then take the string representing the script's domain in IDNA format, encode it as UTF-8, and send that to the remote host, followed by a 0x0A byte (a U+000A LINE FEED in UTF-8).
The user agent must then read all the bytes sent from the remote host, up to the first 0x0A byte (inclusive). That string of bytes must then be compared byte-for-byte to the string that was just sent to the server (the one with the IDNA domain name and ending with a newline character). If the server sent back a string in any way different to this, then the user agent must close the connection and give up trying to connect.
Otherwise, the connection has been established (and events and so forth get fired, as described above).
If at any point during this process the connection is closed prematurely, then the user agent must close the connection and give up trying to connect.
This section defines the server side of the protocol described in the
previous section. For authors, it should be used as a guide for how to
implement servers that can communicate with Web pages over TCP. For UAs
these are the requirements for the server part of PeerToPeerConnection
s.
Once a TCP/IP connection from a remote host is established, the user agent must transmit the following sequence of bytes, represented here in hexadecimal form:
0x57 0x65 0x6C 0x63 0x6F 0x6E 0x65 0x0A
This says "Welcome" and a newline in UTF-8.
The user agent must then read all the bytes sent from the remote host, up to the first 0x0A byte (inclusive). That string of bytes is then compared byte-for-byte to the following string of bytes:
0x48 0x65 0x6C 0x6C 0x6F 0x0A
"Hello" and a newline.
If the remote host sent back a string in any way different to this, then the user agent must close the connection and give up trying to connect.
Otherwise, the user agent must then take the string representing the script's domain in IDNA format, encode it as UTF-8, and send that to the remote host, followed by a 0x0A byte (a U+000A LINE FEED in UTF-8).
The user agent must then read all the bytes sent from the remote host, up to the first 0x0A byte (inclusive). That string of bytes must then be compared byte-for-byte to the string that was just sent to that host (the one with the IDNA domain name and ending with a newline character). If the remote host sent back a string in any way different to this, then the user agent must close the connection and give up trying to connect.
Otherwise, the connection has been established (and events and so forth get fired, as described above).
For author-written servers (as opposed to the server side of a peer-to-peer connection), the script's domain would be replaced by the hostname of the server. Alternatively, such servers might instead wait for the client to send its domain string, and then simply echo it back. This would allow connections from pages on any domain, instead of just pages originating from the same host. The client compares the two strings to ensure they are the same before allowing the connection to be used by author script.
If at any point during this process the connection is closed prematurely, then the user agent must close the connection and give up trying to connect.
When the send(data)
method is invoked on the connection's
corresponding Connection
object,
the user agent must take the data argument, replace
any U+0000 NULL and U+0017 END OF TRANSMISSION BLOCK characters in it with
U+FFFD REPLACEMENT CHARACTER characters, then transmit a U+0002 START OF
TEXT character, this new data string and a single
U+0017 END OF TRANSMISSION BLOCK character (in that order) to the remote
host, all encoded as UTF-8.
When the user agent receives bytes on the connection, the user agent
must buffer received bytes until it receives a 0x17 byte (a U+0017 END OF
TRANSMISSION BLOCK character). If the first buffered byte is not a 0x02
byte (a U+0002 START OF TEXT character encoded as UTF-8) then all the data
up to the 0x17 byte, inclusive, must be dropped. (This allows for future
extension of this protocol.) Otherwise, all the data from (but not
including) the 0x02 byte and up to (but not including) the 0x17 byte must
be taken, interpreted as a UTF-8 string, and a read
event must be
fired on the Connection
object
with that string as the data
. If that string cannot be decoded as UTF-8
without errors, the packet should be ignored.
This protocol does not yet allow binary data (e.g. an image or media data) to be efficiently transmitted. A future version of this protocol might allow this by using the prefix character U+001F INFORMATION SEPARATOR ONE, followed by binary data which uses a particular byte (e.g. 0xFF) to encode byte 0x17 somehow (since otherwise 0x17 would be treated as transmission end by down-level UAs).
Need to write this section.
If you have an unencrypted page that is (through a man-in-the-middle attack) changed, it can access a secure service that is using IP authentication and then send that data back to the attacker. Ergo we should probably stop unencrypted pages from accessing encrypted services, on the principle that the actual level of security is zero. Then again, if we do that, we prevent insecure sites from using SSL as a tunneling mechanism.
Should consider dropping the subdomain-only restriction. It doesn't seem to add anything, and prevents cross-domain chatter.
Should have a section talking about the fact that we blithely ignoring IANA's port assignments here.
Should explain why we are not reusing HTTP for this. (HTTP is too heavy-weight for such a simple need; requiring authors to implement an HTTP server just to have a party line is too much of a barrier to entry; cannot rely on prebuilt components; having a simple protocol makes it much easier to do RAD; HTTP doesn't fit the needs and doesn't have the security model needed; etc)
Web browsers, for security and privacy reasons, prevent documents in different domains from affecting each other; that is, cross-site scripting is disallowed.
While this is an important security feature, it prevents pages from different domains from communicating even when those pages are not hostile. This section introduces a messaging system that allows documents to communicate with each other regardless of their source domain, in a way designed to not enable cross-site scripting attacks.
When a script invokes the postMessage(message)
method on a Window
object, the user agent must create an
event that uses the MessageEvent
interface, with the event name message
, which bubbles, is cancelable, and has
no default action. The data
attribute must be set to the value passed as
the message argument to the postMessage()
method, the domain
attribute must be set to the domain of the document that the script that invoked the
methods is associated with, the uri
attribute must be set to the URI of that
document, and the source
attribute must be set to the Window
object of the default view of the
browsing context with which that document is associated.
Define 'domain' more exactly -- IDN vs no IDN, absence of ports, effect of window.document.domain on its value, etc
The event must then be dispatched at the Document
object
that is the active document of the Window
object on which the method was invoked.
The postMessage()
method must only return once
the event dispatch has been completely processed by the target document
(i.e. all three of the capture, target, and bubble phases have been done,
and event listeners have been executed as appropriate).
Authors should check the domain
attribute to ensure that messages are only accepted from domains that they
expect to receive messages from. Otherwise, bugs in the author's message
handling code could be exploited by hostile sites.
For example, if document A contains an object
element that contains document B, and
script in document A calls postMessage()
on document B, then a
message event will be fired on that element, marked as originating from
document A. The script in document A might look like:
var o = document.getElementsByTagName('object')[0]; o.contentWindow.postMessage('Hello world');
To register an event handler for incoming events, the script would use
addEventListener()
(or similar mechanisms). For
example, the script in document B might look like:
document.addEventListener('message', receiver, false); function receiver(e) { if (e.domain == 'example.com') { if (e.data == 'Hello world') { e.source.postMessage('Hello'); } else { alert(e.data); } } }
This script first checks the domain is the expected domain, and then looks at the message, which it either displays to the user, or responds to by sending a message back to the document which sent the message in the first place.
The integrity of this API is based on the inability for
scripts of one origin to post arbitrary events (using dispatchEvent()
or otherwise) to objects in other origins.
Implementors are urged to take extra care in the implementation of this feature. It allows authors to transmit information from one domain to another domain, which is normally disallowed for security reasons. It also requires that UAs be careful to allow access to certain properties but not others.
See WF2 for now
This section only applies to documents, authoring tools, and markup generators. In particular, it does not apply to conformance checkers; conformance checkers must use the requirements given in the next section ("parsing HTML documents").
Documents must consist of the following parts, in the given order:
html
element.
The various types of content mentioned above are described in the next few sections.
In addition, there are some restrictions on how character encoding declarations are to be serialised, as discussed in the section on that topic.
The U+0000 NULL character must not appear anywhere in a document.
Space characters before the root html
element will be dropped when the document is
parsed; space characters after the root html
element will be parsed as if they were at the
end of the html
element. Thus, space
characters around the root element do not round-trip. It is suggested that
newlines be inserted after the DOCTYPE and any comments that aren't in the
root element.
A DOCTYPE is a mostly useless, but required, header.
DOCTYPEs are required for legacy reasons. When omitted, browsers tend to use a different rendering mode that is incompatible with some specifications. Including the DOCTYPE in a document ensures that the browser makes a best-effort attempt at following the relevant specifications.
A DOCTYPE must consist of the following characters, in this order:
<
) character.
!
) character.
>
) character.
In other words, <!DOCTYPE HTML>
,
case-insensitively.
There are four different kinds of elements: void elements, CDATA elements, RCDATA elements, and normal elements.
base
, link
, meta
,
hr
, br
,
img
, embed
, param
,
area
, col
, input
style
, script
title
, textarea
Tags are used to delimit the start and end of elements in the markup. CDATA, RCDATA, and normal elements have a start tag to indicate where they begin, and an end tag to indicate where they end. The start and end tags of certain normal elements can be omitted, as described later. Those that cannot be omitted must not be omitted. Void elements only have a start tag; end tags must not be specified for void elements.
The contents of the element must be placed between just after the start tag (which might be implied, in certain cases) and just before the end tag (which again, might be implied in certain cases). The exact allowed contents of each individual element depends on the content model of that element, as described earlier in this specification. Elements must not contain content that their content model disallows. In addition to the restrictions placed on the contents by those content models, however, the four types of elements have additional syntactic requirements.
Void elements can't have any contents (since there's no end tag, no content can be put between the start tag and the end tag.)
CDATA elements can have text, though it has restrictions described below.
RCDATA elements can have text and character entity references, but the text must not contain an ambiguous ampersand. There are also further restrictions described below.
Normal elements can have text, character entity references,
other elements, and comments, but the text must
not contain the character U+003C LESS-THAN SIGN (<
) or an
ambiguous
ampersand. Some normal elements also have yet more restrictions on what content
they are allowed to hold, beyond the restrictions imposed by the content
model and those described in this paragraph. Those restrictions are
described below.
Tags contain a tag name,
giving the element's name. HTML elements all have names that only use
characters in the range U+0061 LATIN SMALL LETTER A .. U+007A LATIN SMALL
LETTER Z, or, in uppercase, U+0041 LATIN CAPITAL LETTER A .. U+005A LATIN
CAPITAL LETTER Z, and U+002D HYPHEN-MINUS (-
). In the HTML
syntax, tag names may be written with any mix of lower- and uppercase
letters that, when converted to all-lowercase, matches the element's tag
name; tag names are case-insensitive.
Start tags must have the following format:
<
).
/
) character. This character has no
effect except to appease the markup gods. As this character is therefore
just a symbol of faith, atheists should omit it.
>
) character.
End tags must have the following format:
<
).
/
).
>
) character.
Attributes for an element are expressed inside the element's start tag.
Attributes have a name and a value. Attribute names must consist of one character other than the space characters, U+003E GREATER-THAN SIGN (>), and U+002F SOLIDUS (/), followed by zero or more characters other than the space characters, U+003E GREATER-THAN SIGN (>), U+002F SOLIDUS (/), and U+003D EQUALS SIGN (=). In the HTML syntax, attribute names may be written with any mix of lower- and uppercase letters that, when converted to all-lowercase, matches the attribute's name; attribute names are case-insensitive.
Attribute values are a mixture of text and character entity references, except with the additional restriction that the text cannot contain an ambiguous ampersand.
Attributes can be specified in four different ways:
Just the attribute name.
In the following example, the disabled
attribute is given with the
empty attribute syntax:
<input disabled>
If an attribute using the empty attribute syntax is to be followed by another attribute, then there must be a space character separating the two.
The attribute
name, followed by zero or more space characters, followed by a single U+003D EQUALS SIGN
character, followed by zero or more space characters, followed by the attribute value, which, in addition to
the requirements given above for attribute values, must not contain any
literal space characters or
U+003E GREATER-THAN SIGN (>
) characters, and must not,
furthermore, start with either a literal U+0022 QUOTATION MARK
("
) character or a literal U+0027 APOSTROPHE
('
) character.
In the following example, the value
attribute is given with the
unquoted attribute value syntax:
<input value=yes>
If an attribute using the unquoted attribute syntax is to be followed
by another attribute or by one of the optional U+002F SOLIDUS
(/
) characters allowed in step 6 of the start tag syntax above, then there must be
a space character separating the two.
The attribute
name, followed by zero or more space characters, followed by a single U+003D EQUALS SIGN
character, followed by zero or more space characters, followed by a single U+0027 APOSTROPHE
('
) character, followed by the attribute value, which, in addition to
the requirements given above for attribute values, must not contain any
literal U+0027 APOSTROPHE ('
) characters, and finally
followed by a second single U+0027 APOSTROPHE ('
)
character.
In the following example, the type
attribute is given with the single-quoted attribute value syntax:
<input type='checkbox'>
The attribute
name, followed by zero or more space characters, followed by a single U+003D EQUALS SIGN
character, followed by zero or more space characters, followed by a single U+0022 QUOTATION
MARK ("
) character, followed by the attribute value, which, in addition to
the requirements given above for attribute values, must not contain any
literal U+0022 QUOTATION MARK ("
) characters, and finally
followed by a second single U+0022 QUOTATION MARK ("
)
character.
In the following example, the name
attribute is given with the double-quoted attribute value syntax:
<input name="be evil">
Certain tags can be omitted.
An html
element's start tag may be omitted if the first thing
inside the html
element is not a space character or a comment.
An html
element's end tag may be omitted if the html
element is not immediately followed by a space character or a comment.
A head
element's start tag may be omitted if the first thing
inside the head
element is an element.
A head
element's end tag may be omitted if the head
element is not immediately followed by a space character or a comment.
A body
element's start tag may be omitted if the first thing
inside the body
element is not a space character or a comment, except if the first thing inside the
body
element is a script
or style
element.
A body
element's end tag may be omitted if the body
element is not immediately followed by a space character or a comment.
A li
element's end tag may be omitted if the li
element is immediately followed by another
li
element or if there is no more content
in the parent element.
A dt
element's end tag may be omitted if the dt
element is immediately followed by another
dt
element or a dd
element.
A dd
element's end tag may be omitted if the dd
element is immediately followed by another
dd
element or a dt
element, or if there is no more content in the
parent element.
A p
element's end tag may be omitted if the p
element is immediately followed by an address
, blockquote
, dl
, fieldset
, form
,
h1
, h2
,
h3
, h4
,
h5
, h6
,
hr
, menu
,
ol
, p
,
pre
, table
, or ul
element, or if there is no more content in the parent element.
An optgroup
element's end
tag may be omitted if the optgroup
element is
immediately followed by another optgroup
element, or if there
is no more content in the parent element.
An option
element's end
tag may be omitted if the option
element is
immediately followed by another option
element, or if there
is no more content in the parent element.
A colgroup
element's start tag may be omitted if the first thing
inside the colgroup
element is a
col
element, and if the element is not
immediately preceded by another colgroup
element whose end tag has been omitted.
A colgroup
element's end tag may be omitted if the colgroup
element is not immediately followed
by a space character or a comment.
A thead
element's end tag may be omitted if the thead
element is immediately followed by a
tbody
or tfoot
element.
A tbody
element's start tag may be omitted if the first thing
inside the tbody
element is a tr
element, and if the element is not immediately
preceded by a tbody
, thead
, or tfoot
element whose end tag has been omitted.
A tbody
element's end tag may be omitted if the tbody
element is immediately followed by a
tbody
or tfoot
element, or if there is no more content in
the parent element.
A tfoot
element's end tag may be omitted if the tfoot
element is immediately followed by a
tbody
element, or if there is no more
content in the parent element.
A tr
element's end tag may be omitted if the tr
element is immediately followed by another
tr
element, or if there is no more content
in the parent element.
A td
element's end tag may be omitted if the td
element is immediately followed by a td
or th
element, or
if there is no more content in the parent element.
A th
element's end tag may be omitted if the th
element is immediately followed by a td
or th
element, or
if there is no more content in the parent element.
However, a start tag must never be omitted if it has any attributes.
For historical reasons, certain elements have extra restrictions beyond even the restrictions given by their content model.
A p
element must not contain blockquote
, dl
, menu
, ol
, pre
, table
, or ul
elements, even though these elements are technically allowed inside
p
elements according to the content models
described in this specification. (In fact, if one of those elements is put
inside a p
element in the markup, it will
instead imply a p
element end tag before
it.)
An optgroup
element must not contain optgroup
elements, even though these elements are technically allowed to be nested
according to the content models described in this specification. (If an
optgroup
element is put inside another in the markup, it will
in fact imply an optgroup
end tag before it.)
A table
element must not contain
tr
elements, even though these elements are
technically allowed inside table
elements according to the content models described in this specification.
(If a tr
element is put inside a table
in the markup, it will in fact imply a
tbody
start tag before it.)
A single U+000A LINE FEED (LF) character may be placed immediately after
the start tag of pre
and textarea
elements. This does
not affect the processing of the element. The otherwise optional U+000A
LINE FEED (LF) character must be included if the element's
contents start with that character (because otherwise the leading newline
in the contents would be treated like the optional newline, and ignored).
The text in CDATA and RCDATA elements must not contain any occurences of
the string "</
" (U+003C LESS-THAN SIGN, U+002F
SOLIDUS) followed by characters that case-insensitively match
the tag name of the element followed by one of U+0009 CHARACTER
TABULATION, U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM
FEED (FF), U+0020 SPACE, U+003E GREATER-THAN SIGN (>), or U+002F SOLIDUS
(/), unless that string is part of an escaping text span.
An escaping text span is a span of text (in CDATA and RCDATA elements) and character entity references (in RCDATA elements) that starts with an escaping text span start that is not itself in an escaping text span, and ends at the next escaping text span end.
An escaping text span
start is a part of text that
consists of the four character sequence "<!--
"
(U+003C LESS-THAN SIGN, U+0021 EXCLAMATION MARK, U+002D HYPHEN-MINUS,
U+002D HYPHEN-MINUS).
An escaping text span
end is a part of text that
consists of the three character sequence "-->
"
(U+002D HYPHEN-MINUS, U+002D HYPHEN-MINUS, U+003E GREATER-THAN SIGN) whose
U+003E GREATER-THAN SIGN (>).
An escaping text span start may share its U+002D HYPHEN-MINUS characters with its corresponding escaping text span end.
The text in CDATA and RCDATA elements must not have an escaping text span start that is not followed by an escaping text span end.
Text is allowed inside elements, attributes, and comments. Text must consist of valid Unicode characters other than U+0000. Text should not contain control characters other than space characters. Extra constraints are placed on what is and what is not allowed in text based on where the text is to be put, as described in the other sections.
Newlines in HTML may be represented either as U+000D CARRIAGE RETURN (CR) characters, U+000A LINE FEED (LF) characters, or pairs of U+000D CARRIAGE RETURN (CR), U+000A LINE FEED (LF) characters in that order.
In certain cases described in other sections, text may be mixed with character entity references. These can be used to escape characters that couldn't otherwise legally be included in text.
Character entity references must start with a U+0026 AMPERSAND
(&
). Following this, there are three possible kinds of
character entity references:
;
) character.
#
) character, followed by one or more digits in the range
U+0030 DIGIT ZERO .. U+0039 DIGIT NINE, representing a base-ten integer
that itself is a valid Unicode code point that is not U+0000, U+000D, in
the range U+0080 .. U+009F, or in the range 0xD800 .. 0xDFFF
(surrogates). The digits must then be followed by a U+003B SEMICOLON
character (;
).
#
) character, which must be followed by either a U+0078
LATIN SMALL LETTER X or a U+0058 LATIN CAPITAL LETTER X character, which
must then be followed by one or more digits in the range U+0030 DIGIT
ZERO .. U+0039 DIGIT NINE, U+0061 LATIN SMALL LETTER A .. U+0066 LATIN
SMALL LETTER F, and U+0041 LATIN CAPITAL LETTER A .. U+0046 LATIN CAPITAL
LETTER F, representing a base-sixteen integer that itself is a valid
Unicode code point that is not U+0000, U+000D, in the range U+0080 ..
U+009F, or in the range 0xD800 .. 0xDFFF (surrogates). The digits must
then be followed by a U+003B SEMICOLON character (;
).
An ambiguous
ampersand is a U+0026 AMPERSAND (&
) character that
is not the last character in the file, that is not followed by a space character, that is not followed by a start tag
that has not been omitted, and that is not followed by another U+0026
AMPERSAND (&
) character.
Comments must start with
the four character sequence U+003C LESS-THAN SIGN, U+0021 EXCLAMATION
MARK, U+002D HYPHEN-MINUS, U+002D HYPHEN-MINUS (<!--
). Following this sequence, the comment may have text, with the additional restriction
that the text must not contain two consecutive U+002D HYPHEN-MINUS (-
) characters, nor end with a U+002D HYPHEN-MINUS (-
) character. Finally, the comment must be ended by the
three character sequence U+002D HYPHEN-MINUS, U+002D HYPHEN-MINUS, U+003E
GREATER-THAN SIGN (-->
).
This section only applies to user agents, data mining tools, and conformance checkers.
The rules for parsing XML documents (and thus XHTML documents) into DOM trees are covered by the XML and Namespaces in XML specifications, and are out of scope of this specification. [XML] [XMLNS]
For HTML documents, user agents must use the parsing rules described in this section to generate the DOM trees. Together, these rules define what is referred to as the HTML parser.
While the HTML form of HTML5 bears a close resemblance to SGML and XML, it is a separate language with its own parsing rules.
Some earlier versions of HTML (in particular from HTML2 to HTML4) were based on SGML and used SGML parsing rules. However, few (if any) web browsers ever implemented true SGML parsing for HTML documents; the only user agents to strictly handle HTML as an SGML application have historically been validators. The resulting confusion — with validators claiming documents to have one representation while widely deployed Web browsers interoperably implemented a different representation — has wasted decades of productivity. This version of HTML thus returns to a non-SGML basis.
Authors interested in using SGML tools in their authoring pipeline are encouraged to use XML tools and the XML serialisation of HTML5.
This specification defines the parsing rules for HTML documents, whether they are syntactically valid or not. Certain points in the parsing algorithm are said to be parse errors. The error handling for parse errors is well-defined: user agents must either act as described below when encountering such problems, or must abort processing at the first error that they encounter for which they do not wish to apply the rules described below.
Conformance checkers must report at least one parse error condition to the user if one or more parse error conditions exist in the document and must not report parse error conditions if none exist in the document. Conformance checkers may report more than one parse error condition if more than one parse error conditions exist in the document. Conformance checkers are not required to recover from parse errors.
Parse errors are only errors with the syntax of HTML. In addition to checking for parse errors, conformance checkers will also verify that the document obeys all the other conformance requirements described in this specification.
The input to the HTML parsing process consists of a stream of Unicode
characters, which is passed through a tokenisation stage (lexical analysis) followed
by a tree construction stage (semantic
analysis). The output is a Document
object.
Implementations that do not support
scripting do not have to actually create a DOM Document
object, but the DOM tree in such cases is still used as the model for the
rest of the specification.
In the common case, the data handled by the tokenisation stage comes
from the network, but it can also come from script, e.g. using the document.write()
API.
There is only one set of state for the tokeniser stage and the tree construction stage, but the tree construction stage is reentrant, meaning that while the tree construction stage is handling one token, the tokeniser might be resumed, causing further tokens to be emitted and processed before the first token's processing is complete.
In the following example, the tree construction stage will be called upon to handle a "p" start tag token while handling the "script" start tag token:
... <script> document.write('<p>'); </script> ...
The stream of Unicode characters that consists the input to the tokenisation stage will be initially seen by the user agent as a stream of bytes (typically coming over the network or from the local file system). The bytes encode the actual characters according to a particular character encoding, which the user agent must use to decode the bytes into characters.
For XML documents, the algorithm user agents must use to determine the character encoding is given by the XML specification. This section does not apply to XML documents. [XML]
In some cases, it might be impractical to unambiguously determine the encoding before parsing the document. Because of this, this specification provides for a two-pass mechanism with an optional pre-scan. Implementations are allowed, as described below, to apply a simplified parsing algorithm to whatever bytes they have available before beginning to parse the document. Then, the real parser is started, using a tentative encoding derived from this pre-parse and other out-of-band metadata. If, while the document is being loaded, the user agent discovers an encoding declaration that conflicts with this information, then the parser can get reinvoked to perform a parse of the document with the real encoding.
User agents must use the following algorithm (the encoding sniffing algorithm) to determine the character encoding to use when decoding a document in the first pass. This algorithm takes as input any out-of-band metadata available to the user agent (e.g. the Content-Type metadata of the document) and all the bytes available so far, and returns an encoding and a confidence. The confidence is either tentative or certain. The encoding used, and whether the confidence in that encoding is tentative or confident, is used during the parsing to determine whether to change the encoding.
If the transport layer specifies an encoding, return that encoding with the confidence certain, and abort these steps.
The user agent may wait for more bytes of the resource to be available, either in this step or at any later step in this algorithm. For instance, a user agent might wait 500ms or 512 bytes, whichever came first. In general preparsing the source to find the encoding improves performance, as it reduces the need to throw away the data structures used when parsing upon finding the encoding information. However, if the user agent delays too long to obtain data to determine the encoding, then the cost of the delay could outweigh any performance improvements from the preparse.
For each of the rows in the following table, starting with the first one and going down, if there are as many or more bytes available than the number of bytes in the first column, and the first bytes of the file match the bytes given in the first column, then return the encoding given in the cell in the second column of that row, with the confidence certain, and abort these steps:
| Bytes in Hexadecimal | Description |
|---|---|
| FE FF | UTF-16BE BOM |
| FF FE | UTF-16LE BOM |
| EF BB BF | UTF-8 BOM |
Otherwise, the user agent will have to search for explicit character encoding information in the file itself. This should proceed as follows:
Let position be a pointer to a byte in the input stream, initially pointing at the first byte. If at any point during these substeps the user agent either runs out of bytes or decides that scanning further bytes would not be efficient, then skip to the next step of the overall character encoding detection algorithm. User agents may decide that scanning any bytes is not efficient, in which case these substeps are entirely skipped.
Now, repeat the following "two" steps until the algorithm aborts (either because user agent aborts, as described above, or because a character encoding is found):
If position points to:
Advance the position pointer so that it points at the first 0x3E byte which is preceded by two 0x2D bytes (i.e. at the end of an ASCII '-->' sequence) and comes after the 0x3C byte that was found. (The two 0x2D bytes can be the same as the those in the '<!--' sequence.)
Advance the position pointer so that it points at the next 0x09, 0x0A, 0x0B, 0x0C, 0x0D, or 0x20 byte (the one in sequence of characters matched above).
Get an attribute and its value. If no attribute was sniffed, then skip this inner set of steps, and jump to the second step in the overall "two step" algorithm.
Examine the attribute's name:
If the attribute's value is a supported character encoding, then return the given encoding, with confidence tentative, and abort all these steps. Otherwise, do nothing with this attribute, and continue looking for other attributes.
The attribute's value is now parsed.
Do nothing with that attribute.
Return to step 1 in these inner steps.
Advance the position pointer so that it points at the next 0x09 (ASCII TAB), 0x0A (ASCII LF), 0x0B (ASCII VT), 0x0C (ASCII FF), 0x0D (ASCII CR), 0x20 (ASCII space), 0x3E (ASCII '>'), 0x3C (ASCII '<') byte.
If the pointer points to a 0x3C (ASCII '<') byte, then return to the first step in the overall "two step" algorithm.
Repeatedly get an attribute until no further attributes can be found, then jump to the second step in the overall "two step" algorithm.
Advance the position pointer so that it points at the first 0x3E byte (ASCII '>') that comes after the 0x3C byte that was found.
Do nothing with that byte.
When the above "two step" algorithm says to get an attribute, it means doing this:
If the byte at position is one of 0x09 (ASCII TAB), 0x0A (ASCII LF), 0x0B (ASCII VT), 0x0C (ASCII FF), 0x0D (ASCII CR), 0x20 (ASCII space), or 0x2F (ASCII '/') then advance position to the next byte and start over.
If the byte at position is 0x3C (ASCII '<'), then move position back to the previous byte, and stop looking for an attribute. There isn't one.
If the byte at position is 0x3E (ASCII '>'), then stop looking for an attribute. There isn't one.
Otherwise, the byte at position is the start of the attribute name. Let attribute name and attribute value be the empty string.
Attribute name: Process the byte at position as follows:
Advance position to the next byte and return to the previous step.
Spaces. If the byte at position is one of 0x09 (ASCII TAB), 0x0A (ASCII LF), 0x0B (ASCII VT), 0x0C (ASCII FF), 0x0D (ASCII CR), or 0x20 (ASCII space) then advance position to the next byte, then, repeat this step.
If the byte at position is not 0x3D (ASCII '='), stop looking for an attribute. Move position back to the previous byte. The attribute's name is the value of attribute name, its value is the empty string.
Advance position past the 0x3D (ASCII '=') byte.
Value. If the byte at position is one of 0x09 (ASCII TAB), 0x0A (ASCII LF), 0x0B (ASCII VT), 0x0C (ASCII FF), 0x0D (ASCII CR), or 0x20 (ASCII space) then advance position to the next byte, then, repeat this step.
Process the byte at position as follows:
Process the byte at position as follows:
Advance position to the next byte and return to the previous step.
For the sake of interoperability, user agents should not use a pre-scan algorithm that returns different results than the one described above. (But, if you do, please at least let us know, so that we can improve this algorithm and benefit everyone...)
If the user agent has information on the likely encoding for this page, e.g. based on the encoding of the page when it was last visited, then return that encoding, with the confidence tentative, and abort these steps.
The user agent may attempt to autodetect the character encoding from applying frequency analysis or other algorithms to the data stream. If autodetection succeeds in determining a character encoding, then return that encoding, with the confidence tentative, and abort these steps. [UNIVCHARDET]
Otherwise, return an implementation-defined or user-specified default
character encoding, with the confidence tentative. Due
to its use in legacy content, windows-1252
is
recommended as a default in predominantly Western demographics. In
non-legacy environments, the more comprehensive UTF-8
encoding is recommended instead. Since these
encodings can in many cases be distinguished by inspection, a user agent
may heuristically decide which to use as a default.
User agents must at a minimum support the UTF-8 and Windows-1252 encodings, but may support more.
It is not unusual for Web browsers to support dozens if not upwards of a hundred distinct character encodings.
User agents must support the preferred MIME name of every character encoding they support that has a preferred MIME name, and should support all the IANA-registered aliases. [IANACHARSET]
When a user agent would otherwise use the ISO-8859-1 encoding, it must instead use the Windows-1252 encoding.
This requirement is a willful violation of the W3C Character Model specification. [CHARMOD]
User agents must not support the CESU-8, UTF-7, BOCU-1 and SCSU encodings. [CESU8] [UTF7] [BOCU1] [SCSU]
Support for UTF-32 is not recommended. This encoding is rarely used, and frequently misimplemented.
Given an encoding, the bytes in the input stream must be converted to Unicode characters for the tokeniser, as described by the rules for that encoding, except that leading U+FEFF BYTE ORDER MARK characters must not be stripped by the encoding layer.
Bytes or sequences of bytes in the original byte stream that could not be converted to Unicode characters must be converted to U+FFFD REPLACEMENT CHARACTER code points.
One leading U+FEFF BYTE ORDER MARK character must be ignored if any are present.
All U+0000 NULL characters in the input must be replaced by U+FFFD REPLACEMENT CHARACTERs. Any occurrences of such characters is a parse error.
U+000D CARRIAGE RETURN (CR) characters, and U+000A LINE FEED (LF) characters, are treated specially. Any CR characters that are followed by LF characters must be removed, and any CR characters not followed by LF characters must be converted to LF characters. Thus, newlines in HTML DOMs are represented by LF characters, and there are never any CR characters in the input to the tokenisation stage.
The next input character is the first character in the input stream that has not yet been consumed. Initially, the next input character is the first character in the input.
The insertion point is the position (just before
a character or just before the end of the input stream) where content
inserted using document.write()
is actually
inserted. The insertion point is relative to the position of the character
immediately after it, it is not an absolute offset into the input stream.
Initially, the insertion point is uninitialised.
The "EOF" character in the tables below is a conceptual character
representing the end of the input stream. If the
parser is a script-created parser, then the
end of the input stream is reached when an explicit "EOF" character (inserted by the document.close()
method) is consumed. Otherwise, the "EOF" character is not a real
character in the stream, but rather the lack of any further characters.
When the parser requires the user agent to change the encoding, it must run the following steps. This might happen if the encoding sniffing algorithm described above failed to find an encoding, or if it found an encoding that was not the actual encoding of the file.
While the invocation of this algorithm is not a parse error, it is still indicative of non-conforming content.
Implementations must act as if they used the following state machine to tokenise HTML. The state machine must start in the data state. Most states consume a single character, which may have various side-effects, and either switches the state machine to a new state to reconsume the same character, or switches it to a new state (to consume the next character), or repeats the same state (to consume the next character). Some states have more complicated behaviour and can consume several characters before switching to another state.
The exact behaviour of certain states depends on a content model flag that is set after certain tokens are emitted. The flag has several states: PCDATA, RCDATA, CDATA, and PLAINTEXT. Initially it must be in the PCDATA state. In the RCDATA and CDATA states, a further escape flag is used to control the behaviour of the tokeniser. It is either true or false, and initially must be set to the false state.
The output of the tokenisation step is a series of zero or more of the following tokens: DOCTYPE, start tag, end tag, comment, character, end-of-file. DOCTYPE tokens have a name, a public identifier, a system identifier, and a correctness flag. When a DOCTYPE token is created, its name, public identifier, and system identifier must be marked as missing, and the correctness flag must be set to correct (its other state is incorrect). Start and end tag tokens have a tag name and a list of attributes, each of which has a name and a value. Comment and character tokens have data.
When a token is emitted, it must immediately be handled by the tree construction stage. The tree
construction stage can affect the state of the content
model flag, and can insert additional characters into the stream. (For
example, the script
element can result
in scripts executing and using the dynamic markup
insertion APIs to insert characters into the stream being tokenised.)
When an end tag token is emitted, the content model flag must be switched to the PCDATA state.
When an end tag token is emitted with attributes, that is a parse error.
A permitted slash is a U+002F SOLIDUS character
that is immediately followed by a U+003E GREATER-THAN SIGN, if, and only
if, the current token being processed is a start tag token whose tag name
is one of the following: base
, link
, meta
,
hr
, br
,
img
, embed
, param
,
area
, col
, input
Before each step of the tokeniser, the user agent may check to see if either one of the scripts in the list of scripts that will execute as soon as possible or the first script in the list of scripts that will execute asynchronously, has completed loading. If one has, then it must be executed and removed from its list.
The tokeniser state machine is as follows:
Consume the next input character:
If the content model flag is set to either the RCDATA state or the CDATA state, and the escape flag is false, and there are at least three characters before this one in the input stream, and the last four characters in the input stream, including this one, are U+003C LESS-THAN SIGN, U+0021 EXCLAMATION MARK, U+002D HYPHEN-MINUS, and U+002D HYPHEN-MINUS ("<!--"), then set the escape flag to true.
In any case, emit the input character as a character token. Stay in the data state.
If the content model flag is set to either the RCDATA state or the CDATA state, and the escape flag is true, and the last three characters in the input stream including this one are U+002D HYPHEN-MINUS, U+002D HYPHEN-MINUS, U+003E GREATER-THAN SIGN ("-->"), set the escape flag to false.
In any case, emit the input character as a character token. Stay in the data state.
(This cannot happen if the content model flag is set to the CDATA state.)
Attempt to consume an entity.
If nothing is returned, emit a U+0026 AMPERSAND character token.
Otherwise, emit the character token that was returned.
Finally, switch to the data state.
The behaviour of this state depends on the content model flag.
Consume the next input character. If it is a U+002F SOLIDUS (/) character, switch to the close tag open state. Otherwise, emit a U+003C LESS-THAN SIGN character token and reconsume the current input character in the data state.
Consume the next input character:
If the content model flag is set to the RCDATA or CDATA states but no start tag token has ever been emitted by this instance of the tokeniser (fragment case), or, if the content model flag is set to the RCDATA or CDATA states and the next few characters do not match the tag name of the last start tag token emitted (case insensitively), or if they do but they are not immediately followed by one of the following characters:
...then emit a U+003C LESS-THAN SIGN character token, a U+002F SOLIDUS character token, and switch to the data state to process the next input character.
Otherwise, if the content model flag is set to the PCDATA state, or if the next few characters do match that tag name, consume the next input character:
Consume the next input character:
Consume the next input character:
Consume the next input character:
When the user agent leaves the attribute name state (and before emitting the tag token, if appropriate), the complete attribute's name must be compared to the other attributes on the same token; if there is already an attribute on the token with the exact same name, then this is a parse error and the new attribute must be dropped, along with the value that gets associated with it (if any).
Consume the next input character:
Consume the next input character:
Consume the next input character:
Consume the next input character:
Consume the next input character:
Attempt to consume an entity.
If nothing is returned, append a U+0026 AMPERSAND character to the current attribute's value.
Otherwise, append the returned character token to the current attribute's value.
Finally, switch back to the attribute value state that you were in when were switched into this state.
(This can only happen if the content model flag is set to the PCDATA state.)
Consume every character up to the first U+003E GREATER-THAN SIGN character (>) or the end of the file (EOF), whichever comes first. Emit a comment token whose data is the concatenation of all the characters starting from and including the character that caused the state machine to switch into the bogus comment state, up to and including the last consumed character before the U+003E character, if any, or up to the end of the file otherwise. (If the comment was started by the end of the file (EOF), the token is empty.)
Switch to the data state.
If the end of the file was reached, reconsume the EOF character.
(This can only happen if the content model flag is set to the PCDATA state.)
If the next two characters are both U+002D HYPHEN-MINUS (-) characters, consume those two characters, create a comment token whose data is the empty string, and switch to the comment start state.
Otherwise if the next seven characters are a case-insensitive match for the word "DOCTYPE", then consume those characters and switch to the DOCTYPE state.
Otherwise, is is a parse error. Switch to the bogus comment state. The next character that is consumed, if any, is the first character that will be in the comment.
Consume the next input character:
Consume the next input character:
Consume the next input character:
Consume the next input character:
Consume the next input character:
Consume the next input character:
Consume the next input character:
First, consume the next input character:
Consume the next input character:
If the next six characters are a case-insensitive match for the word "PUBLIC", then consume those characters and switch to the before DOCTYPE public identifier state.
Otherwise, if the next six characters are a case-insensitive match for the word "SYSTEM", then consume those characters and switch to the before DOCTYPE system identifier state.
Otherwise, this is the parse error. Switch to the bogus DOCTYPE state.
Consume the next input character:
Consume the next input character:
Consume the next input character:
Consume the next input character:
Consume the next input character:
Consume the next input character:
Consume the next input character:
Consume the next input character:
Consume the next input character:
This section defines how to consume an entity. This definition is used when parsing entities in text and in attributes.
The behaviour depends on the identity of the next character (the one immediately after the U+0026 AMPERSAND character):
Consume the U+0023 NUMBER SIGN.
The behaviour further depends on the character after the U+0023 NUMBER SIGN:
Consume the X.
Follow the steps below, but using the range of characters U+0030 DIGIT ZERO through to U+0039 DIGIT NINE, U+0061 LATIN SMALL LETTER A through to U+0066 LATIN SMALL LETTER F, and U+0041 LATIN CAPITAL LETTER A, through to U+0046 LATIN CAPITAL LETTER F (in other words, 0-9, A-F, a-f).
When it comes to interpreting the number, interpret it as a hexadecimal number.
Follow the steps below, but using the range of characters U+0030 DIGIT ZERO through to U+0039 DIGIT NINE (i.e. just 0-9).
When it comes to interpreting the number, interpret it as a decimal number.
Consume as many characters as match the range of characters given above.
If no characters match the range, then don't consume any characters (and unconsume the U+0023 NUMBER SIGN character and, if appropriate, the X character). This is a parse error; nothing is returned.
Otherwise, if the next character is a U+003B SEMICOLON, consume that too. If it isn't, there is a parse error.
If one or more characters match the range, then take them all and interpret the string of characters as a number (either hexadecimal or decimal as appropriate).
If that number is one of the numbers in the first column of the following table, then this is a parse error. Find the row with that number in the first column, and return a character token for the Unicode character given in the second column of that row.
| Number | Unicode character | |
|---|---|---|
| 0x0D | U+000A | LINE FEED (LF) |
| 0x80 | U+20AC | EURO SIGN ('€') |
| 0x81 | U+FFFD | REPLACEMENT CHARACTER |
| 0x82 | U+201A | SINGLE LOW-9 QUOTATION MARK ('‚') |
| 0x83 | U+0192 | LATIN SMALL LETTER F WITH HOOK ('ƒ') |
| 0x84 | U+201E | DOUBLE LOW-9 QUOTATION MARK ('„') |
| 0x85 | U+2026 | HORIZONTAL ELLIPSIS ('…') |
| 0x86 | U+2020 | DAGGER ('†') |
| 0x87 | U+2021 | DOUBLE DAGGER ('‡') |
| 0x88 | U+02C6 | MODIFIER LETTER CIRCUMFLEX ACCENT ('ˆ') |
| 0x89 | U+2030 | PER MILLE SIGN ('‰') |
| 0x8A | U+0160 | LATIN CAPITAL LETTER S WITH CARON ('Š') |
| 0x8B | U+2039 | SINGLE LEFT-POINTING ANGLE QUOTATION MARK ('‹') |
| 0x8C | U+0152 | LATIN CAPITAL LIGATURE OE ('Œ') |
| 0x8D | U+FFFD | REPLACEMENT CHARACTER |
| 0x8E | U+017D | LATIN CAPITAL LETTER Z WITH CARON ('Ž') |
| 0x8F | U+FFFD | REPLACEMENT CHARACTER |
| 0x90 | U+FFFD | REPLACEMENT CHARACTER |
| 0x91 | U+2018 | LEFT SINGLE QUOTATION MARK ('‘') |
| 0x92 | U+2019 | RIGHT SINGLE QUOTATION MARK ('’') |
| 0x93 | U+201C | LEFT DOUBLE QUOTATION MARK ('“') |
| 0x94 | U+201D | RIGHT DOUBLE QUOTATION MARK ('”') |
| 0x95 | U+2022 | BULLET ('•') |
| 0x96 | U+2013 | EN DASH ('–') |
| 0x97 | U+2014 | EM DASH ('—') |
| 0x98 | U+02DC | SMALL TILDE ('˜') |
| 0x99 | U+2122 | TRADE MARK SIGN ('™') |
| 0x9A | U+0161 | LATIN SMALL LETTER S WITH CARON ('š') |
| 0x9B | U+203A | SINGLE RIGHT-POINTING ANGLE QUOTATION MARK ('›') |
| 0x9C | U+0153 | LATIN SMALL LIGATURE OE ('œ') |
| 0x9D | U+FFFD | REPLACEMENT CHARACTER |
| 0x9E | U+017E | LATIN SMALL LETTER Z WITH CARON ('ž') |
| 0x9F | U+0178 | LATIN CAPITAL LETTER Y WITH DIAERESIS ('Ÿ') |
Otherwise, if the number is zero, if the number is higher than 0x10FFFF, or if it's one of the surrogate characters (characters in the range 0xD800 to 0xDFFF), then this is a parse error; return a character token for the U+FFFD REPLACEMENT CHARACTER character instead.
Otherwise, return a character token for the Unicode character whose code point is that number.
Consume the maximum number of characters possible, with the consumed characters case-sensitively matching one of the identifiers in the first column of the entities table.
If no match can be made, then this is a parse error. No characters are consumed, and nothing is returned.
If the last character matched is not a U+003B SEMICOLON (;
), there is a parse error.
If the entity is being consumed as part of an attribute, and the last
character matched is not a U+003B SEMICOLON (;
),
and the next character is in the range U+0030 DIGIT ZERO to U+0039 DIGIT
NINE, U+0041 LATIN CAPITAL LETTER A to U+005A LATIN CAPITAL LETTER Z, or
U+0061 LATIN SMALL LETTER A to U+007A LATIN SMALL LETTER Z, then, for
historical reasons, all the characters that were matched after the
U+0026 AMPERSAND (&) must be unconsumed, and nothing is returned.
Otherwise, return a character token for the character corresponding to the entity name (as given by the second column of the entities table).
If the markup contains I'm ¬it; I tell
you
, the entity is parsed as "not", as in, I'm
¬it; I tell you
. But if the markup was I'm
∉ I tell you
, the entity would be parsed as "notin;",
resulting in I'm ∉ I tell you
.
The input to the tree construction stage is a sequence of tokens from
the tokenisation stage. The tree construction
stage is associated with a DOM Document
object when a parser
is created. The "output" of this stage consists of dynamically modifying
or extending that document's DOM tree.
Tree construction passes through several phases. Initially, UAs must act according to the steps described as being those of the initial phase.
This specification does not define when an interactive user agent has to
render the Document
available to the user, or when it has to
begin accepting user input.
When the steps below require the UA to append a
character to a node, the UA must collect it and all subsequent
consecutive characters that would be appended to that node, and insert one
Text
node whose data is the concatenation of all those
characters.
DOM mutation events must not fire for changes
caused by the UA parsing the document. (Conceptually, the parser is not
mutating the DOM, it is constructing it.) This includes the parsing of any
content inserted using document.write()
and document.writeln()
calls.
[DOM3EVENTS]
Not all of the tag names mentioned below are conformant tag names in this specification; many are included to handle legacy content. They still form part of the algorithm that implementations are required to implement to claim conformance.
The algorithm described below places no limit on the depth of the DOM tree generated, or on the length of tag names, attribute names, attribute values, text nodes, etc. While implementators are encouraged to avoid arbitrary limits, it is recognised that practical concerns will likely force user agents to impose nesting depths.
Initially, the tree construction stage must handle each token emitted from the tokenisation stage as follows:
Ignore the token.
Append a Comment
node to the Document
object
with the data
attribute set to the data given in
the comment token.
If the DOCTYPE token's name
does not
case-insensitively match the string "HTML
", or if
the token's public identifier is not missing, or if the token's system
identifier is not missing, then there is a parse
error. Conformance checkers may, instead of reporting this error,
switch to a conformance checking mode for another language (e.g. based
on the DOCTYPE token a conformance checker could recognise that the
document is an HTML4-era document, and defer to an HTML4 conformance
checker.)
Append a DocumentType
node to the Document
node, with the name
attribute set to the name
given in the DOCTYPE token; the publicId
attribute
set to the public identifier given in the DOCTYPE token, or the empty
string if the public identifier was not set; the systemId
attribute set to the system identifier given in
the DOCTYPE token, or the empty string if the system identifier was not
set; and the other attributes specific to DocumentType
objects set to null and empty lists as appropriate. Associate the
DocumentType
node with the Document
object so
that it is returned as the value of the doctype
attribute of the Document
object.
Then, if the DOCTYPE token matches one of the conditions in the following list, then set the document to quirks mode:
HTML
".
+//Silmaril//dtd
html Pro v0r11 19970101//EN
"
-//AdvaSoft
Ltd//DTD HTML 3.0 asWedit + extensions//EN
"
-//AS//DTD HTML
3.0 asWedit + extensions//EN
"
-//IETF//DTD HTML
2.0 Level 1//EN
"
-//IETF//DTD HTML
2.0 Level 2//EN
"
-//IETF//DTD HTML
2.0 Strict Level 1//EN
"
-//IETF//DTD HTML
2.0 Strict Level 2//EN
"
-//IETF//DTD HTML
2.0 Strict//EN
"
-//IETF//DTD HTML
2.0//EN
"
-//IETF//DTD HTML
2.1E//EN
"
-//IETF//DTD HTML
3.0//EN
"
-//IETF//DTD HTML
3.0//EN//
"
-//IETF//DTD HTML
3.2 Final//EN
"
-//IETF//DTD HTML
3.2//EN
"
-//IETF//DTD HTML
3//EN
"
-//IETF//DTD HTML
Level 0//EN
"
-//IETF//DTD HTML
Level 0//EN//2.0
"
-//IETF//DTD HTML
Level 1//EN
"
-//IETF//DTD HTML
Level 1//EN//2.0
"
-//IETF//DTD HTML
Level 2//EN
"
-//IETF//DTD HTML
Level 2//EN//2.0
"
-//IETF//DTD HTML
Level 3//EN
"
-//IETF//DTD HTML
Level 3//EN//3.0
"
-//IETF//DTD HTML
Strict Level 0//EN
"
-//IETF//DTD HTML
Strict Level 0//EN//2.0
"
-//IETF//DTD HTML
Strict Level 1//EN
"
-//IETF//DTD HTML
Strict Level 1//EN//2.0
"
-//IETF//DTD HTML
Strict Level 2//EN
"
-//IETF//DTD HTML
Strict Level 2//EN//2.0
"
-//IETF//DTD HTML
Strict Level 3//EN
"
-//IETF//DTD HTML
Strict Level 3//EN//3.0
"
-//IETF//DTD HTML
Strict//EN
"
-//IETF//DTD HTML
Strict//EN//2.0
"
-//IETF//DTD HTML
Strict//EN//3.0
"
-//IETF//DTD
HTML//EN
"
-//IETF//DTD
HTML//EN//2.0
"
-//IETF//DTD
HTML//EN//3.0
"
-//Metrius//DTD
Metrius Presentational//EN
"
-//Microsoft//DTD
Internet Explorer 2.0 HTML Strict//EN
"
-//Microsoft//DTD
Internet Explorer 2.0 HTML//EN
"
-//Microsoft//DTD
Internet Explorer 2.0 Tables//EN
"
-//Microsoft//DTD
Internet Explorer 3.0 HTML Strict//EN
"
-//Microsoft//DTD
Internet Explorer 3.0 HTML//EN
"
-//Microsoft//DTD
Internet Explorer 3.0 Tables//EN
"
-//Netscape Comm.
Corp.//DTD HTML//EN
"
-//Netscape Comm.
Corp.//DTD Strict HTML//EN
"
-//O'Reilly and
Associates//DTD HTML 2.0//EN
"
-//O'Reilly and
Associates//DTD HTML Extended 1.0//EN
"
-//Spyglass//DTD
HTML 2.0 Extended//EN
"
-//SQ//DTD HTML
2.0 HoTMetaL + extensions//EN
"
-//Sun
Microsystems Corp.//DTD HotJava HTML//EN
"
-//Sun
Microsystems Corp.//DTD HotJava Strict HTML//EN
"
-//W3C//DTD HTML 3
1995-03-24//EN
"
-//W3C//DTD HTML
3.2 Draft//EN
"
-//W3C//DTD HTML
3.2 Final//EN
"
-//W3C//DTD HTML
3.2//EN
"
-//W3C//DTD HTML
3.2S Draft//EN
"
-//W3C//DTD HTML
4.0 Frameset//EN
"
-//W3C//DTD HTML
4.0 Transitional//EN
"
-//W3C//DTD HTML
Experimental 19960712//EN
"
-//W3C//DTD HTML
Experimental 970421//EN
"
-//W3C//DTD W3
HTML//EN
"
-//W3O//DTD W3
HTML 3.0//EN
"
-//W3O//DTD W3
HTML 3.0//EN//
"
-//W3O//DTD W3
HTML Strict 3.0//EN//
"
-//WebTechs//DTD
Mozilla HTML 2.0//EN
"
-//WebTechs//DTD
Mozilla HTML//EN
"
-/W3C/DTD HTML 4.0
Transitional/EN
"
HTML
"
http://www.ibm.com/data/dtd/v11/ibmxhtml1-transitional.dtd
"
-//W3C//DTD HTML 4.01 Frameset//EN
"
-//W3C//DTD HTML 4.01 Transitional//EN
"
Otherwise, if the DOCTYPE token matches one of the conditions in the following list, then set the document to limited quirks mode:
-//W3C//DTD XHTML
1.0 Frameset//EN
"
-//W3C//DTD XHTML
1.0 Transitional//EN
"
-//W3C//DTD HTML 4.01 Frameset//EN
"
-//W3C//DTD HTML 4.01 Transitional//EN
"
The name, system identifier, and public identifier strings must be compared to the values given in the lists above in a case-insensitive manner.
Then, switch to the root element phase of the tree construction stage.
Set the document to quirks mode.
Then, switch to the root element phase of the tree construction stage and reprocess the current token.
After the initial phase, as each token is emitted from the tokenisation stage, it must be processed as described in this section.
Parse error. Ignore the token.
Append a Comment
node to the Document
object
with the data
attribute set to the data given in
the comment token.
Ignore the token.
If the token is a start tag token with the tag name "html", and it has an attribute "application", then run the application cache selection algorithm with the value of that attribute as the manifest URI. Otherwise, run the application cache selection algorithm with no manifest.
Create an HTMLElement
node
with the tag name html
, in the HTML namespace. Append it to the
Document
object. Switch to the main
phase and reprocess the current token.
Should probably make end tags be ignored, so that "</head><!-- --><html>" puts the comment before the root node (or should we?)
The root element can end up being removed from the Document
object, e.g. by scripts; nothing in particular happens in such cases,
content continues being appended to the nodes as described in the next
section.
After the root element phase, each token emitted from the tokenisation stage must be processed as described in this section. This is by far the most involved part of parsing an HTML document.
The tree construction stage in this phase has several pieces of state: a
stack of open elements, a list of
active formatting elements, a head
element pointer, a form
element pointer, and an insertion mode.
We could just fold insertion modes and phases into one concept (and duplicate the two rules common to all insertion modes into all of them).
Initially the stack of open elements contains just
the html
root element node created in the
last phase before
switching to this phase (or, in the fragment
case, the html
element created as
part of that algorithm). That's the topmost node of the stack. It
never gets popped off the stack. (This stack grows downwards.)
The current node is the bottommost node in this stack.
Elements in the stack fall into the following categories:
The following HTML elements have varying levels of special parsing
rules: address
, area
, base
,
basefont
, bgsound
, blockquote
, body
, br
,
center
, col
, colgroup
, dd
,
dir
, div
, dl
, dt
, embed
, fieldset
,
form
, frame
, frameset
, h1
, h2
, h3
, h4
, h5
, h6
, head
, hr
,
iframe
,
image
,
img
, input
,
isindex
, li
, link
, listing
, menu
, meta
,
noembed
, noframes
, noscript
, ol
,
optgroup
, option
, p
, param
,
plaintext
, pre
, script
, select
,
spacer
, style
, tbody
, textarea
, tfoot
, thead
, title
, tr
,
ul
, and wbr
.
The following HTML elements introduce new scopes for various parts of the
parsing: button
, caption
, html
, marquee
, object
, table
, td
and
th
.
The following HTML elements are those that end up in the list of active formatting elements: a
, b
,
big
, em
, font
, i
,
nobr
, s
, small
, strike
, strong
, tt
, and u
.
All other elements found while parsing an HTML document.
Still need to add these new elements to the lists:
event-source
, section
, nav
,
article
, aside
, header
,
footer
, datagrid
, command
The stack of open elements is said to have an element in scope or have an element in table scope when the following algorithm terminates in a match state:
Initialise node to be the current node (the bottommost node of the stack).
If node is the target node, terminate in a match state.
Otherwise, if node is a table
element, terminate in a failure state.
Otherwise, if the algorithm is the "has an element in scope" variant (rather than the "has an element in table scope" variant), and node is one of the following, terminate in a failure state:
Otherwise, if node is an html
element, terminate in a failure state.
(This can only happen if the node is the topmost
node of the stack of open elements, and prevents
the next step from being invoked if there are no more elements in the
stack.)
Otherwise, set node to the previous entry in the stack of open elements and return to step 2. (This will never fail, since the loop will always terminate in the previous step if the top of the stack is reached.)
Nothing happens if at any time any of the elements in the stack of open elements are moved to a new location in,
or removed from, the Document
tree. In particular, the stack
is not changed in this situation. This can cause, amongst other strange
effects, content to be appended to nodes that are no longer in the DOM.
In some cases (namely, when closing misnested formatting elements), the stack is manipulated in a random-access fashion.
Initially the list of active formatting elements is empty. It is used to handle mis-nested formatting element tags.
The list contains elements in the formatting
category, and scope markers. The scope markers are inserted when entering
buttons, object
elements, marquees,
table cells, and table captions, and are used to prevent formatting from
"leaking" into tables, buttons, object
elements, and marquees.
When the steps below require the UA to reconstruct the active formatting elements, the UA must perform the following steps:
This has the effect of reopening all the formatting elements that were opened in the current body, cell, or caption (whichever is youngest) that haven't been explicitly closed.
The way this specification is written, the list of active formatting elements always consists of elements in chronological order with the least recently added element first and the most recently added element last (except for while steps 8 to 11 of the above algorithm are being executed, of course).
When the steps below require the UA to clear the list of active formatting elements up to the last marker, the UA must perform the following steps:
When the steps below require the UA to create an element for a token, the UA must
create a node implementing the interface appropriate for the element type
corresponding to the tag name of the token (as given in the section of
this specification that defines that element, e.g. for an a
element it would be the HTMLAnchorElement
interface), with
the tag name being the name of that element, with the node being in the HTML namespace, and with the attributes on the
node being those given in the given token.
When the steps below require the UA to insert an HTML element for a token, the UA must first create an element for the token, and then append this node to the current node, and push it onto the stack of open elements so that it is the new current node.
The steps below may also require that the UA insert an HTML element in a particular place, in which case the UA must create an element for the token and then insert or append the new node in the location specified. (This happens in particular during the parsing of tables with invalid content.)
The interface appropriate for an element that is not defined in this
specification is HTMLElement
.
The generic CDATA parsing algorithm and the generic RCDATA parsing algorithm consist of the following steps. These algorithms are always invoked in response to a start tag token, and are always passed a context node, typically the current node, which is used as the place to insert the resulting element node.
Append the new element to the given context node.
If the algorithm that was invoked is the generic CDATA parsing algorithm, switch the tokeniser's content model flag to the CDATA state; otherwise the algorithm invoked was the generic RCDATA parsing algorithm, switch the tokeniser's content model flag to the RCDATA state.
Then, collect all the character tokens that the tokeniser returns until it returns a token that is not a character token, or until it stops tokenising.
If this process resulted in a collection of character tokens, append a
single Text
node, whose contents is the concatenation of
all those tokens' characters, to the new element node.
The tokeniser's content model flag will have switched back to the PCDATA state.
If the next token is an end tag token with the same tag name as the start tag token, ignore it. Otherwise, this is a parse error.
When the steps below require the UA to generate implied
end tags, then, if the current node is a
dd
element, a dt
element, an li
element, a p
element, a tbody
element, a td
element, a tfoot
element, a th
element, a thead
element, a tr
element, the UA must act as if an end tag with
the respective tag name had been seen and then generate implied end tags again.
The step that requires the UA to generate implied end tags but lists an element to exclude from the process, then the UA must perform the above steps as if that element was not in the above list.
Initially the head
element
pointer and the form
element pointer are both null.
Once a head
element has been parsed
(whether implicitly or explicitly) the head
element pointer gets set to point to this node.
The form
element
pointer points to the last form
element that was opened
and whose end tag has not yet been seen. It is used to make form controls
associate with forms in the face of dramatically bad markup, for
historical reasons.
Initially the insertion mode is "before head". It can change to "in head", "in head noscript", "after head", "in body", "in table", "in caption", "in column group", "in table body", "in row", "in cell", "in select", "after body", "in frameset", and "after frameset" during the course of the parsing, as described below. It affects how certain tokens are processed.
If the tree construction stage is switched from the main phase to the trailing end phase and back again, the various pieces of state are not reset; the UA must act as if the state was maintained.
When the steps below require the UA to reset the insertion mode appropriately, it means the UA must follow these steps:
td
element nor a
th
element, then set node to the context element. (fragment case)
select
element, then
switch the insertion mode to "in select" and
abort these steps. (fragment case)
td
or
th
element, then switch the insertion mode to "in cell" and abort these steps.
tr
element, then switch the insertion mode to "in row" and abort these
steps.
tbody
, thead
,
or tfoot
element, then switch the insertion mode to "in table body" and abort these
steps.
caption
element, then switch the insertion mode to "in caption" and abort these steps.
colgroup
element, then switch the insertion mode to "in column group" and abort
these steps. (fragment case)
table
element, then switch the insertion mode to "in table" and abort these steps.
head
element, then switch the insertion mode to "in body" ("in body"! not
"in head"!)
and abort these steps. (fragment case)body
element, then switch the insertion mode to "in body" and abort these steps.
frameset
element, then
switch the insertion mode to "in frameset"
and abort these steps. (fragment case)
html
element, then: if the head
element pointer is
null, switch the insertion mode to "before head",
otherwise, switch the insertion mode to "after head". In
either case, abort these steps. (fragment case)Tokens in the main phase must be handled as follows:
Parse error. Ignore the token.
If this start tag token was not the first start tag token, then it is a parse error.
For each attribute on the token, check to see if the attribute is already present on the top element of the stack of open elements. If it is not, add the attribute and its corresponding value to that element.
If there are more than two nodes on the stack of open
elements, or if there are two nodes but the second node is not a
body
node, this is a parse error.
Otherwise, if the parser was originally created as part of the HTML fragment parsing algorithm, and there's
more than one element in the stack of open
elements, and the second node on the stack of open
elements is not a body
node, then
this is a parse error. (fragment case)
This fails because it doesn't imply HEAD and BODY tags. We should probably expand out the insertion modes and merge them with phases and then put the three things here into each insertion mode instead of trying to factor them out so carefully.
Depends on the insertion mode:
Handle the token as follows:
Append the character to the current node.
Append a Comment
node to the current node with the data
attribute set to the data given in the comment
token.
Create an element for the token.
Set the head
element
pointer to this new element node.
Append the new element to the current node and push it onto the stack of open elements.
Change the insertion mode to "in head".
Act as if a start tag token with the tag name "head" and no attributes had been seen, then reprocess the current token.
This will result in a head
element being generated, and with the
current token being reprocessed in the "in head" insertion mode.
Act as if a start tag token with the tag name "head" and no attributes had been seen, then reprocess the current token.
Parse error. Ignore the token.
Do we really want to ignore end tags here?
Act as if a start tag token with the tag name "head" and no attributes had been seen, then reprocess the current token.
This will result in an empty head
element being generated, with the
current token being reprocessed in the "after head" insertion mode.
Handle the token as follows.
Append the character to the current node.
Append a Comment
node to the current node with the data
attribute set to the data given in the comment
token.
Insert an HTML element for the token.
Insert an HTML element for the token.
If the element has a charset
attribute, and its value is a supported encoding, and the confidence
is currently tentative, then change the
encoding to the encoding given by the value of the charset
attribute.
Otherwise, if the element has a content
attribute, and applying the
algorithm to extract an encoding from a Content-Type to
its value returns a supported encoding encoding,
and the confidence is currently
tentative, then change the encoding to
the encoding encoding.
Follow the generic RCDATA parsing
algorithm, with the head
element pointer as the context node, unless
that's null, in which case use the current
node (fragment cose).
Follow the generic CDATA parsing algorithm, with the current node as the context node.
Insert a
noscript
element for the token.
Change the insertion mode to "in head noscript".
Create an element for the token.
Mark the element as being "parser-inserted". This ensures that, if
the script is external, any document.write()
calls in the
script will execute in-line, instead of blowing the document away,
as would happen in most other cases.
Switch the tokeniser's content model flag to the CDATA state.
Then, collect all the character tokens that the tokeniser returns until it returns a token that is not a character token, or until it stops tokenising.
If this process resulted in a collection of character tokens,
append a single Text
node to the script
element node whose contents is the
concatenation of all those tokens' characters.
The tokeniser's content model flag will have switched back to the PCDATA state.
If the next token is not an end tag token with the tag name
"script", then this is a parse error; mark the
script
element as "already executed". Otherwise, the token is the
script
element's end tag, so
ignore it.
If the parser was originally created for the HTML fragment parsing algorithm, then
mark the script
element as "already executed", and skip the rest of the
processing described for this token (including the part below where
"scripts that will execute as soon as the
parser resumes" are executed). (fragment
case)
Marking the script
element as "already executed" prevents it from executing when it is
inserted into the document a few paragraphs below. Thus, scripts
missing their end tags and scripts that were inserted using innerHTML
aren't executed.
Let the old insertion point have the same value as the current insertion point. Let the insertion point be just before the next input character.
Append the new element to the current
node. Special
processing occurs when a script
element is inserted
into a document that might cause some script to execute, which
might cause new characters to be inserted into the
tokeniser.
Let the insertion point have the value of the old insertion point. (In other words, restore the insertion point to the value it had before the previous paragraph. This value might be the "undefined" value.)
At this stage, if there is a script that will execute as soon as the parser resumes, then:
document.write()
:
Abort the processing of any nested invokations of the tokeniser, yielding control back to the caller. (Tokenisation will resume when the caller returns to the "outer" tree construction stage.)
Follow these steps:
Let the script be the script that will execute as soon as the parser resumes. There is no longer a script that will execute as soon as the parser resumes.
Pause until the script has completed loading.
Let the insertion point be just before the next input character.
Let the insertion point be undefined again.
If there is once again a script that will execute as soon as the parser resumes, then repeat these steps from step 1.
Pop the current node (which will be the
head
element) off the stack of open elements.
Change the insertion mode to "after head".
Act as described in the "anything else" entry below.
Parse error. Ignore the token.
Act as if an end tag token with the tag name "head" had been seen, and reprocess the current token.
In certain UAs, some elements don't trigger the "in body" mode straight away, but instead get put into the head. Do we want to copy that?
Pop the current node (which will be a
noscript
element) from the stack of open elements; the new current node will be a head
element.
Switch the insertion mode to "in head".
Process the token as if the insertion mode had been "in head".
Act as described in the "anything else" entry below.
Parse error. Ignore the token.
Parse error. Act as if an end tag with the tag name "noscript" had been seen and reprocess the current token.
Handle the token as follows:
Append the character to the current node.
Append a Comment
node to the current node with the data
attribute set to the data given in the comment
token.
Insert a
body
element for the token.
Change the insertion mode to "in body".
Insert a
frameset
element for the token.
Change the insertion mode to "in frameset".
Push the node pointed to by the head
element pointer onto the stack of open elements.
Process the token as if the insertion mode had been "in head".
Pop the current node (which will be the
node pointed to by the head
element pointer) off the stack of open elements.
Act as if a start tag token with the tag name "body" and no attributes had been seen, and then reprocess the current token.
Handle the token as follows:
Append a Comment
node to the current node with the data
attribute set to the data given in the comment
token.
Process the token as if the insertion mode had been "in head".
Parse error. Process the token as if the insertion mode had been "in head".
If the second element on the stack of open
elements is not a body
element, or, if the stack of open elements has
only one node on it, then ignore the token. (fragment case)
Otherwise, for each attribute on the token, check to see if the
attribute is already present on the body
element (the second element) on the stack of open elements. If it is not, add the
attribute and its corresponding value to that element.
If the second element in the stack of open
elements is not a body
element, this is a parse error. Ignore the
token. (fragment case)
Otherwise, if there is a node in the stack of
open elements that is not either a dd
element, a dt
element, an li
element, a p
element, a tbody
element, a
td
element, a tfoot
element, a th
element, a thead
element, a tr
element, the body
element, or the html
element, then this is a parse error.
Change the insertion mode to "after body".
Act as if an end tag with tag name "body" had been seen, then, if that token wasn't ignored, reprocess the current token.
The fake end tag token here can only be ignored in the fragment case.
This doesn't match browsers.
If the stack of open elements has a p
element in scope, then act as if an end tag with the tag name
p
had been seen.
Insert an HTML element for the token.
If the stack of open elements has a p
element in scope, then act as if an end tag with the tag name
p
had been seen.
Insert an HTML element for the token.
If the next token is a U+000A LINE FEED (LF) character token, then
ignore that token and move on to the next one. (Newlines at the
start of pre
blocks are ignored as
an authoring convenience.)
If the form
element pointer is not null, ignore the token with a parse error.
Otherwise:
If the stack of open elements has a p
element in scope, then act as if an end tag with the tag name
p
had been seen.
Insert an HTML
element for the token, and set the form
element pointer to point to the element created.
If the stack of open elements has a p
element in scope, then act as if an end tag with the tag name
p
had been seen.
Run the following algorithm:
Initialise node to be the current node (the bottommost node of the stack).
If node is an li
element, then pop all the nodes from the
current node up to node, including node, then stop
this algorithm. If more than one node is popped, then this is a parse error.
If node is not in the formatting category, and is not in the phrasing category, and is not an address
or div
element, then stop this algorithm.
Otherwise, set node to the previous entry in the stack of open elements and return to step 2.
Finally, insert
an li
element.
If the stack of open elements has a p
element in scope, then act as if an end tag with the tag name
p
had been seen.
Run the following algorithm:
Initialise node to be the current node (the bottommost node of the stack).
If node is a dd
or dt
element, then pop all the nodes from the current node up to node,
including node, then stop this algorithm. If
more than one node is popped, then this is a parse error.
If node is not in the formatting category, and is not in the phrasing category, and is not an address
or div
element, then stop this algorithm.
Otherwise, set node to the previous entry in the stack of open elements and return to step 2.
Finally, insert an HTML element with the same tag name as the token's.
If the stack of open elements has a p
element in scope, then act as if an end tag with the tag name
p
had been seen.
Insert an HTML element for the token.
Switch the content model flag to the PLAINTEXT state.
Once a start tag with the tag name "plaintext" has been seen, that will be the last token ever seen other than character tokens (and the end-of-file token), because there is no way to switch the content model flag out of the PLAINTEXT state.
If the stack of open elements has an element in scope with the same tag name as that of the token, then generate implied end tags.
Now, if the current node is not an element with the same tag name as that of the token, then this is a parse error.
If the stack of open elements has an element in scope with the same tag name as that of the token, then pop elements from this stack until an element with that tag name has been popped from the stack.
If the stack of open elements has an element in scope with the same tag name as that of the token, then generate implied end tags.
Now, if the current node is not an element with the same tag name as that of the token, then this is a parse error.
Otherwise, if the current node is an element with the same tag name as that of the token pop that element from the stack.
In any case, set the form
element pointer to null.
If the stack of open elements has a p
element in scope, then generate implied end
tags, except for p
elements.
If the current node is not a p
element, then this is a parse error.
If the stack of open elements has a p
element in scope, then pop elements from this stack until the
stack no longer has a p
element in scope.
Otherwise, act as if a start tag with the tag name p
had been seen, then reprocess the current
token.
If the stack of open elements has an element in scope whose tag name matches the tag name of the token, then generate implied end tags, except for elements with the same tag name as the token.
If the current node is not an element with the same tag name as the token, then this is a parse error.
If the stack of open elements has an element in scope whose tag name matches the tag name of the token, then pop elements from this stack until an element with that tag name has been popped from the stack.
If the stack of open elements has a p
element in scope, then act as if an end tag with the tag name
p
had been seen.
Insert an HTML element for the token.
If the stack of open elements has in scope an element whose tag name is one of "h1", "h2", "h3", "h4", "h5", or "h6", then generate implied end tags.
Now, if the current node is not an element with the same tag name as that of the token, then this is a parse error.
If the stack of open elements has in scope an element whose tag name is one of "h1", "h2", "h3", "h4", "h5", or "h6", then pop elements from the stack until an element with one of those tag names has been popped from the stack.
If the list of active formatting elements contains an element whose tag name is "a" between the end of the list and the last marker on the list (or the start of the list if there is no marker on the list), then this is a parse error; act as if an end tag with the tag name "a" had been seen, then remove that element from the list of active formatting elements and the stack of open elements if the end tag didn't already remove it (it might not have if the element is not in table scope).
In the non-conforming stream
<a href="a">a<table><a href="b">b</table>x
,
the first a
element would be closed
upon seeing the second one, and the "x" character would be inside a
link to "b", not to "a". This is despite the fact that the outer
a
element is not in table scope
(meaning that a regular </a>
end tag at the start of
the table wouldn't close the outer a
element).
Reconstruct the active formatting elements, if any.
Insert an HTML element for the token. Add that element to the list of active formatting elements.
Reconstruct the active formatting elements, if any.
Insert an HTML element for the token. Add that element to the list of active formatting elements.
Reconstruct the active formatting elements, if any.
If the stack of open elements has a
nobr
element in scope, then this is a parse error. Act as if an end tag with the tag
name nobr
had been seen, then once again reconstruct the active formatting elements,
if any.
Insert an HTML element for the token. Add that element to the list of active formatting elements.
Follow these steps:
Let the formatting element be the last element in the list of active formatting elements that:
If there is no such node, or, if that node is also in the stack of open elements but the element is not in scope, then this is a parse error. Abort these steps. The token is ignored.
Otherwise, if there is such a node, but that node is not in the stack of open elements, then this is a parse error; remove the element from the list, and abort these steps.
Otherwise, there is a formatting element and that element is in the stack and is in scope. If the element is not the current node, this is a parse error. In any case, proceed with the algorithm as written in the following steps.
Let the furthest block be the topmost node in the stack of open elements that is lower in the stack than the formatting element, and is not an element in the phrasing or formatting categories. There might not be one.
If there is no furthest block, then the UA must skip the subsequent steps and instead just pop all the nodes from the bottom of the stack of open elements, from the current node up to and including the formatting element, and remove the formatting element from the list of active formatting elements.
Let the common ancestor be the element immediately above the formatting element in the stack of open elements.
If the furthest block has a parent node, then remove the furthest block from its parent node.
Let a bookmark note the position of the formatting element in the list of active formatting elements relative to the elements on either side of it in the list.
Let node and last node be the furthest block. Follow these steps:
Insert whatever last node ended up being in the previous step into the common ancestor node, first removing it from its previous parent node if any.
Perform a shallow clone of the formatting element.
Take all of the child nodes of the furthest block and append them to the clone created in the last step.
Append that clone to the furthest block.
Remove the formatting element from the list of active formatting elements, and insert the clone into the list of active formatting elements at the position of the aforementioned bookmark.
Remove the formatting element from the stack of open elements, and insert the clone into the stack of open elements immediately after (i.e. in a more deeply nested position than) the position of the furthest block in that stack.
Jump back to step 1 in this series of steps.
The way these steps are defined, only elements in the formatting category ever get cloned by this algorithm.
Because of the way this algorithm causes elements to change parents, it has been dubbed the "adoption agency algorithm" (in contrast with other possibly algorithms for dealing with misnested content, which included the "incest algorithm", the "secret affair algorithm", and the "Heisenberg algorithm").
If the stack of open elements has a
button
element in scope, then this is a parse error; act as if an end tag with the tag
name "button" had been seen, then reprocess the token.
Otherwise:
Reconstruct the active formatting elements, if any.
Insert an HTML element for the token.
Insert a marker at the end of the list of active formatting elements.
Reconstruct the active formatting elements, if any.
Insert an HTML element for the token.
Insert a marker at the end of the list of active formatting elements.
If the stack of open elements has in scope an element whose tag name is the same as the tag name of the token, then generate implied end tags.
Now, if the current node is not an element with the same tag name as the token, then this is a parse error.
Now, if the stack of open elements has an element in scope whose tag name matches the tag name of the token, then pop elements from the stack until that element has been popped from the stack, and clear the list of active formatting elements up to the last marker.
Reconstruct the active formatting elements, if any.
Follow the generic CDATA parsing algorithm, with the current node as the context node.
If the stack of open elements has a p
element in scope, then act as if an end tag with the tag name
p
had been seen.
Insert an HTML element for the token.
Change the insertion mode to "in table".
Reconstruct the active formatting elements, if any.
Insert an HTML element for the token. Immediately pop the current node off the stack of open elements.
If the stack of open elements has a p
element in scope, then act as if an end tag with the tag name
p
had been seen.
Insert an HTML element for the token. Immediately pop the current node off the stack of open elements.
Parse error. Change the token's tag name to "img" and reprocess it. (Don't ask.)
Reconstruct the active formatting elements, if any.
Insert an
input
element for the token.
If the form
element
pointer is not null, then associate
the input
element with the form
element
pointed to by the form
element pointer.
Pop that input
element off the stack
of open elements.
If the form
element
pointer is not null, then ignore the token.
Otherwise:
Act as if a start tag token with the tag name "form" had been seen.
If the token has an attribute called "action", set the action
attribute on the resulting
form
element to the value of the "action" attribute of
the token.
Act as if a start tag token with the tag name "hr" had been seen.
Act as if a start tag token with the tag name "p" had been seen.
Act as if a start tag token with the tag name "label" had been seen.
Act as if a stream of character tokens had been seen (see below for what they should say).
Act as if a start tag token with the tag name "input" had been
seen, with all the attributes from the "isindex" token except
"name", "action", and "prompt". Set the name
attribute of the resulting
input
element to the value "isindex
".
Act as if a stream of character tokens had been seen (see below for what they should say).
Act as if an end tag token with the tag name "label" had been seen.
Act as if an end tag token with the tag name "p" had been seen.
Act as if a start tag token with the tag name "hr" had been seen.
Act as if an end tag token with the tag name "form" had been seen.
If the token has an attribute with the name "prompt", then the
first stream of characters must be the same string as given in that
attribute, and the second stream of characters must be empty.
Otherwise, the two streams of character tokens together should,
together with the input
element, express the equivalent
of "This is a searchable index. Insert your search keywords here:
(input field)" in the user's preferred language.
Then need to specify that if the form submission causes just a single form control, whose name is "isindex", to be submitted, then we submit just the value part, not the "isindex=" part.
Create an element for the token.
If the form
element
pointer is not null, then associate
the textarea
element with the form
element
pointed to by the form
element pointer.
Append the new element to the current node.
Switch the tokeniser's content model flag to the RCDATA state.
If the next token is a U+000A LINE FEED (LF) character token, then
ignore that token and move on to the next one. (Newlines at the
start of textarea
elements are ignored as an authoring
convenience.)
Then, collect all the character tokens that the tokeniser returns until it returns a token that is not a character token, or until it stops tokenising.
If this process resulted in a collection of character tokens,
append a single Text
node, whose contents is the
concatenation of all those tokens' characters, to the new element
node.
The tokeniser's content model flag will have switched back to the PCDATA state.
If the next token is an end tag token with the tag name "textarea", ignore it. Otherwise, this is a parse error.
Follow the generic CDATA parsing algorithm, with the current node as the context node.
Reconstruct the active formatting elements, if any.
Insert an HTML element for the token.
Change the insertion mode to "in select".
Parse error. Act as if a start tag token with the tag name "br" had been seen. Ignore the end tag token.
Parse error. Ignore the token.
Work in progress!
Reconstruct the active formatting elements, if any.
Insert an HTML element for the token.
This element will be a phrasing element.
Run the following algorithm:
Initialise node to be the current node (the bottommost node of the stack).
If node has the same tag name as the end tag token, then:
If the tag name of the end tag token does not match the tag name of the current node, this is a parse error.
Pop all the nodes from the current node up to node, including node, then stop this algorithm.
Otherwise, if node is in neither the formatting category nor the phrasing category, then this is a parse error. Stop this algorithm. The end tag token is ignored.
Set node to the previous entry in the stack of open elements.
Return to step 2.
Append the character to the current node.
Append a Comment
node to the current node with the data
attribute set to the data given in the comment
token.
Clear the stack back to a table context. (See below.)
Insert a marker at the end of the list of active formatting elements.
Insert an HTML element for the token, then switch the insertion mode to "in caption".
Clear the stack back to a table context. (See below.)
Insert an HTML element for the token, then switch the insertion mode to "in column group".
Act as if a start tag token with the tag name "colgroup" had been seen, then reprocess the current token.
Clear the stack back to a table context. (See below.)
Insert an HTML element for the token, then switch the insertion mode to "in table body".
Act as if a start tag token with the tag name "tbody" had been seen, then reprocess the current token.
Parse error. Act as if an end tag token with the tag name "table" had been seen, then, if that token wasn't ignored, reprocess the current token.
The fake end tag token here can only be ignored in the fragment case.
If the stack of open elements does not have an element in table scope with the same tag name as the token, this is a parse error. Ignore the token. (fragment case)
Otherwise:
Now, if the current node is not a table
element, then this is a parse error.
Pop elements from this stack until a table
element has been popped from the
stack.
Parse error. Ignore the token.
Parse error. Process the token as if the insertion mode was "in body", with the following exception:
If the current node is a table
, tbody
, tfoot
, thead
, or tr
element, then, whenever a node would be
inserted into the current node, it must
instead be inserted into the foster parent
element.
The foster parent element is the parent
element of the last table
element
in the stack of open elements, if there is a
table
element and it has such a
parent element. If there is no table
element in the stack
of open elements (fragment case), then
the foster parent element is the
first element in the stack of open elements
(the html
element). Otherwise, if
there is a table
element in the stack of open elements, but the last table
element in the stack
of open elements has no parent, or its parent node is not an
element, then the foster parent
element is the element before the last table
element in the stack
of open elements.
If the foster parent element is the
parent element of the last table
element in the stack of open elements, then the
new node must be inserted immediately before the last
table
element in the stack of open elements in the foster parent element; otherwise, the new node
must be appended to the foster parent
element.
When the steps above require the UA to clear the
stack back to a table context, it means that the UA must, while
the current node is not a table
element or an html
element, pop elements from the stack of open elements. If this causes any elements
to be popped from the stack, then this is a parse
error.
The current node being an
html
element after this process is a
fragment case.
If the stack of open elements does not have an element in table scope with the same tag name as the token, this is a parse error. Ignore the token. (fragment case)
Otherwise:
Now, if the current node is not a caption
element, then this is a parse error.
Pop elements from this stack until a caption
element has been popped from the
stack.
Clear the list of active formatting elements up to the last marker.
Switch the insertion mode to "in table".
Parse error. Act as if an end tag with the tag name "caption" had been seen, then, if that token wasn't ignored, reprocess the current token.
The fake end tag token here can only be ignored in the fragment case.
Parse error. Ignore the token.
Process the token as if the insertion mode was "in body".
Append the character to the current node.
Append a Comment
node to the current node with the data
attribute set to the data given in the comment
token.
Insert a
col
element for the token. Immediately pop the current node off the stack of
open elements.
If the current node is the root html
element, then this is a parse error, ignore the token. (fragment case)
Otherwise, pop the current node (which
will be a colgroup
element)
from the stack of open elements. Switch the insertion mode to "in table".
Parse error. Ignore the token.
Act as if an end tag with the tag name "colgroup" had been seen, and then, if that token wasn't ignored, reprocess the current token.
The fake end tag token here can only be ignored in the fragment case.
Clear the stack back to a table body context. (See below.)
Insert a
tr
element for the token, then switch the insertion mode to "in row".
Parse error. Act as if a start tag with the tag name "tr" had been seen, then reprocess the current token.
If the stack of open elements does not have an element in table scope with the same tag name as the token, this is a parse error. Ignore the token.
Otherwise:
Clear the stack back to a table body context. (See below.)
Pop the current node from the stack of open elements. Switch the insertion mode to "in table".
If the stack of open elements does not have a
tbody
, thead
, or tfoot
element in table scope, this is a parse
error. Ignore the token. (fragment case)
Otherwise:
Clear the stack back to a table body context. (See below.)
Act as if an end tag with the same tag name as the current node ("tbody", "tfoot", or "thead") had been seen, then reprocess the current token.
Parse error. Ignore the token.
Process the token as if the insertion mode was "in table".
When the steps above require the UA to clear the
stack back to a table body context, it means that the UA must,
while the current node is not a tbody
, tfoot
, thead
, or html
element, pop elements from the stack of open elements. If this causes any elements
to be popped from the stack, then this is a parse
error.
The current node being an
html
element after this process is a
fragment case.
Clear the stack back to a table row context. (See below.)
Insert an HTML element for the token, then switch the insertion mode to "in cell".
Insert a marker at the end of the list of active formatting elements.
If the stack of open elements does not have an element in table scope with the same tag name as the token, this is a parse error. Ignore the token. (fragment case)
Otherwise:
Clear the stack back to a table row context. (See below.)
Pop the current node (which will be a
tr
element) from the stack of open elements. Switch the insertion mode to "in table body".
Act as if an end tag with the tag name "tr" had been seen, then, if that token wasn't ignored, reprocess the current token.
The fake end tag token here can only be ignored in the fragment case.
If the stack of open elements does not have an element in table scope with the same tag name as the token, this is a parse error. Ignore the token.
Otherwise, act as if an end tag with the tag name "tr" had been seen, then reprocess the current token.
Parse error. Ignore the token.
Process the token as if the insertion mode was "in table".
When the steps above require the UA to clear the
stack back to a table row context, it means that the UA must,
while the current node is not a tr
element or an html
element, pop elements from the stack of open elements. If this causes any elements
to be popped from the stack, then this is a parse
error.
The current node being an
html
element after this process is a
fragment case.
If the stack of open elements does not have an element in table scope with the same tag name as that of the token, then this is a parse error and the token must be ignored.
Otherwise:
Generate implied end tags, except for elements with the same tag name as the token.
Now, if the current node is not an element with the same tag name as the token, then this is a parse error.
Pop elements from this stack until an element with the same tag name as the token has been popped from the stack.
Clear the list of active formatting elements up to the last marker.
Switch the insertion mode to "in row". (The current node will be a tr
element at this point.)
If the stack of open elements does
not have a td
or th
element in table
scope, then this is a parse error; ignore
the token. (fragment case)
Otherwise, close the cell (see below) and reprocess the current token.
Parse error. Ignore the token.
If the stack of open elements does not have an element in table scope with the same tag name as that of the token (which can only happen for "tbody", "tfoot" and "thead", or, in the fragment case), then this is a parse error and the token must be ignored.
Otherwise, close the cell (see below) and reprocess the current token.
Process the token as if the insertion mode was "in body".
Where the steps above say to close the cell, they mean to run the following algorithm:
If the stack of open elements has a
td
element in table scope, then act as if an end
tag token with the tag name "td" had been seen.
Otherwise, the stack of open elements will have a
th
element in table scope; act as if an end tag
token with the tag name "th" had been seen.
The stack of open elements cannot
have both a td
and a th
element in table scope at the same time, nor can
it have neither when the insertion mode is
"in cell".
Handle the token as follows:
Append a Comment
node to the current node with the data
attribute set to the data given in the comment
token.
If the current node is an
option
element, act as if an end tag with the tag name
"option" had been seen.
Insert an HTML element for the token.
If the current node is an
option