2014-05-06 22:50:34 +00:00
|
|
|
%%machine base_lexer;
|
|
|
|
|
|
|
|
%%{
|
2014-05-07 22:21:23 +00:00
|
|
|
##
|
|
|
|
# Base grammar for the XML lexer.
|
|
|
|
#
|
|
|
|
# This grammar is shared between the C and Java extensions. As a result of
|
|
|
|
# this you should **not** include language specific code in Ragel
|
|
|
|
# actions/callbacks.
|
|
|
|
#
|
|
|
|
# To call back in to Ruby you can use one of the following two functions:
|
|
|
|
#
|
|
|
|
# * callback
|
|
|
|
# * callback_simple
|
|
|
|
#
|
|
|
|
# The first function takes 5 arguments:
|
|
|
|
#
|
|
|
|
# * The name of the Ruby method to call.
|
|
|
|
# * The input data.
|
|
|
|
# * The encoding of the input data.
|
|
|
|
# * The start of the current buffer.
|
|
|
|
# * The end of the current buffer.
|
|
|
|
#
|
|
|
|
# The function callback_simple only takes one argument: the name of the
|
|
|
|
# method to call. This function should be used for callbacks that don't
|
|
|
|
# require any values.
|
|
|
|
#
|
|
|
|
# When you call a method in Ruby make sure that said method is defined as
|
|
|
|
# an instance method in the `Oga::XML::Lexer` class.
|
2014-05-20 22:21:21 +00:00
|
|
|
#
|
2014-11-23 19:20:14 +00:00
|
|
|
# The name of the callback to invoke should be an identifier starting with
|
|
|
|
# "id_". The identifier should be defined in the associated C and Java code.
|
2014-11-29 11:53:55 +00:00
|
|
|
# In case of C code its value should be a Symbol as a ID object, for Java
|
2014-11-23 19:20:14 +00:00
|
|
|
# it should be a String. For example:
|
|
|
|
#
|
2014-11-29 11:53:55 +00:00
|
|
|
# ID id_foo = rb_intern("foo");
|
2014-11-23 19:20:14 +00:00
|
|
|
#
|
|
|
|
# And for Java:
|
|
|
|
#
|
|
|
|
# String id_foo = "foo";
|
|
|
|
#
|
2014-05-20 22:21:21 +00:00
|
|
|
# ## Machine Transitions
|
|
|
|
#
|
|
|
|
# To transition from one machine to another always use `fnext` instead of
|
|
|
|
# `fcall` and `fret`. This removes the need for the code to keep track of a
|
|
|
|
# stack.
|
|
|
|
#
|
2014-05-07 22:21:23 +00:00
|
|
|
|
2015-04-15 18:22:14 +00:00
|
|
|
newline = '\r\n' | '\n' | '\r';
|
|
|
|
whitespace = [ \t];
|
|
|
|
ident_char = [a-zA-Z0-9\-_];
|
|
|
|
identifier = ident_char+;
|
|
|
|
|
|
|
|
whitespace_or_newline = whitespace | newline;
|
2014-09-25 20:49:11 +00:00
|
|
|
|
|
|
|
action count_newlines {
|
|
|
|
if ( fc == '\n' ) lines++;
|
|
|
|
}
|
|
|
|
|
2015-04-15 18:22:14 +00:00
|
|
|
action advance_newline {
|
|
|
|
advance_line(1)
|
|
|
|
}
|
2014-05-06 22:50:34 +00:00
|
|
|
|
2015-04-15 20:33:53 +00:00
|
|
|
action hold_and_return {
|
|
|
|
fhold;
|
|
|
|
fret;
|
|
|
|
}
|
|
|
|
|
2014-05-20 22:21:21 +00:00
|
|
|
# Comments
|
|
|
|
#
|
2015-04-15 20:56:25 +00:00
|
|
|
# http://www.w3.org/TR/html/syntax.html#comments
|
2014-05-20 22:21:21 +00:00
|
|
|
#
|
2015-04-15 20:56:25 +00:00
|
|
|
# Unlike the W3C specification these rules *do* allow character sequences
|
2014-05-20 22:21:21 +00:00
|
|
|
# such as `--` and `->`. Putting extra checks in for these sequences would
|
|
|
|
# actually make the rules/actions more complex.
|
|
|
|
#
|
2014-08-15 18:36:40 +00:00
|
|
|
|
|
|
|
comment_start = '<!--';
|
|
|
|
comment_end = '-->';
|
2015-04-14 21:11:22 +00:00
|
|
|
|
|
|
|
# Everything except "-" OR a single "-"
|
|
|
|
comment_allowed = (^'-'+ | '-') $count_newlines;
|
2014-08-15 18:36:40 +00:00
|
|
|
|
|
|
|
action start_comment {
|
2015-04-14 21:11:22 +00:00
|
|
|
callback_simple(id_on_comment_start);
|
|
|
|
|
|
|
|
fnext comment_body;
|
2014-08-15 18:36:40 +00:00
|
|
|
}
|
|
|
|
|
2015-04-14 21:11:22 +00:00
|
|
|
comment_body := |*
|
|
|
|
comment_allowed => {
|
|
|
|
callback(id_on_comment_body, data, encoding, ts, te);
|
|
|
|
|
|
|
|
if ( lines > 0 )
|
|
|
|
{
|
|
|
|
advance_line(lines);
|
|
|
|
|
|
|
|
lines = 0;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
comment_end => {
|
|
|
|
callback_simple(id_on_comment_end);
|
|
|
|
|
|
|
|
fnext main;
|
|
|
|
};
|
|
|
|
*|;
|
|
|
|
|
2014-05-20 22:21:21 +00:00
|
|
|
# CDATA
|
|
|
|
#
|
2015-04-15 20:56:25 +00:00
|
|
|
# http://www.w3.org/TR/html/syntax.html#cdata-sections
|
2014-05-20 22:21:21 +00:00
|
|
|
#
|
|
|
|
# In HTML CDATA tags have no meaning/are not supported. Oga does
|
|
|
|
# support them but treats their contents as plain text.
|
|
|
|
#
|
2014-08-15 18:47:58 +00:00
|
|
|
|
|
|
|
cdata_start = '<![CDATA[';
|
|
|
|
cdata_end = ']]>';
|
2015-04-14 20:45:55 +00:00
|
|
|
|
|
|
|
# Everything except "]" OR a single "]"
|
|
|
|
cdata_allowed = (^']'+ | ']') $count_newlines;
|
2014-08-15 18:47:58 +00:00
|
|
|
|
|
|
|
action start_cdata {
|
2015-04-14 20:45:55 +00:00
|
|
|
callback_simple(id_on_cdata_start);
|
|
|
|
|
|
|
|
fnext cdata_body;
|
2014-08-15 18:47:58 +00:00
|
|
|
}
|
|
|
|
|
2015-04-14 20:45:55 +00:00
|
|
|
cdata_body := |*
|
|
|
|
cdata_allowed => {
|
|
|
|
callback(id_on_cdata_body, data, encoding, ts, te);
|
|
|
|
|
|
|
|
if ( lines > 0 )
|
|
|
|
{
|
|
|
|
advance_line(lines);
|
|
|
|
|
|
|
|
lines = 0;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
cdata_end => {
|
|
|
|
callback_simple(id_on_cdata_end);
|
|
|
|
|
|
|
|
fnext main;
|
|
|
|
};
|
|
|
|
*|;
|
|
|
|
|
2014-08-15 20:04:45 +00:00
|
|
|
# Processing Instructions
|
|
|
|
#
|
|
|
|
# http://www.w3.org/TR/xpath/#section-Processing-Instruction-Nodes
|
|
|
|
# http://en.wikipedia.org/wiki/Processing_Instruction
|
|
|
|
#
|
|
|
|
# These are tags meant to be used by parsers/libraries for custom behaviour.
|
|
|
|
# One example are the tags used by PHP: <?php and ?>. Note that the XML
|
|
|
|
# declaration tags (<?xml ?>) are not considered to be a processing
|
|
|
|
# instruction.
|
|
|
|
#
|
|
|
|
|
|
|
|
proc_ins_start = '<?' identifier;
|
|
|
|
proc_ins_end = '?>';
|
|
|
|
|
2015-04-14 22:11:57 +00:00
|
|
|
# Everything except "?" OR a single "?"
|
|
|
|
proc_ins_allowed = (^'?'+ | '?') $count_newlines;
|
|
|
|
|
2014-08-15 20:04:45 +00:00
|
|
|
action start_proc_ins {
|
2014-11-21 00:37:33 +00:00
|
|
|
callback_simple(id_on_proc_ins_start);
|
|
|
|
callback(id_on_proc_ins_name, data, encoding, ts + 2, te);
|
2014-08-15 20:04:45 +00:00
|
|
|
|
|
|
|
fnext proc_ins_body;
|
|
|
|
}
|
|
|
|
|
|
|
|
proc_ins_body := |*
|
2015-04-14 22:11:57 +00:00
|
|
|
proc_ins_allowed => {
|
|
|
|
callback(id_on_proc_ins_body, data, encoding, ts, te);
|
|
|
|
|
|
|
|
if ( lines > 0 )
|
|
|
|
{
|
|
|
|
advance_line(lines);
|
|
|
|
|
|
|
|
lines = 0;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2014-08-15 20:04:45 +00:00
|
|
|
proc_ins_end => {
|
2014-11-21 00:37:33 +00:00
|
|
|
callback_simple(id_on_proc_ins_end);
|
2014-08-15 20:04:45 +00:00
|
|
|
|
|
|
|
fnext main;
|
|
|
|
};
|
|
|
|
*|;
|
|
|
|
|
2014-05-06 22:50:34 +00:00
|
|
|
# Strings
|
|
|
|
#
|
|
|
|
# Strings in HTML can either be single or double quoted. If a string
|
|
|
|
# starts with one of these quotes it must be closed with the same type
|
|
|
|
# of quote.
|
2014-05-20 22:21:21 +00:00
|
|
|
#
|
2014-05-06 22:50:34 +00:00
|
|
|
dquote = '"';
|
|
|
|
squote = "'";
|
|
|
|
|
2014-10-26 10:39:56 +00:00
|
|
|
action emit_string {
|
2014-11-21 00:37:33 +00:00
|
|
|
callback(id_on_string_body, data, encoding, ts, te);
|
2014-05-06 22:50:34 +00:00
|
|
|
|
2014-10-26 10:39:56 +00:00
|
|
|
if ( lines > 0 )
|
|
|
|
{
|
|
|
|
advance_line(lines);
|
2014-05-06 22:50:34 +00:00
|
|
|
|
2014-10-26 10:39:56 +00:00
|
|
|
lines = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
action start_string_squote {
|
2014-11-21 00:37:33 +00:00
|
|
|
callback_simple(id_on_string_squote);
|
2014-10-26 10:39:56 +00:00
|
|
|
|
|
|
|
fcall string_squote;
|
2014-05-19 18:26:07 +00:00
|
|
|
}
|
2014-05-06 22:50:34 +00:00
|
|
|
|
2014-10-26 10:39:56 +00:00
|
|
|
action start_string_dquote {
|
2014-11-21 00:37:33 +00:00
|
|
|
callback_simple(id_on_string_dquote);
|
2014-10-26 10:39:56 +00:00
|
|
|
|
|
|
|
fcall string_dquote;
|
|
|
|
}
|
|
|
|
|
|
|
|
string_squote := |*
|
|
|
|
^squote* $count_newlines => emit_string;
|
|
|
|
|
|
|
|
squote => {
|
2014-11-21 00:37:33 +00:00
|
|
|
callback_simple(id_on_string_squote);
|
2014-10-26 10:39:56 +00:00
|
|
|
|
|
|
|
fret;
|
|
|
|
};
|
|
|
|
*|;
|
|
|
|
|
|
|
|
string_dquote := |*
|
|
|
|
^dquote* $count_newlines => emit_string;
|
|
|
|
|
|
|
|
dquote => {
|
2014-11-21 00:37:33 +00:00
|
|
|
callback_simple(id_on_string_dquote);
|
2014-10-26 10:39:56 +00:00
|
|
|
|
|
|
|
fret;
|
|
|
|
};
|
|
|
|
*|;
|
|
|
|
|
2014-05-06 22:50:34 +00:00
|
|
|
# DOCTYPES
|
|
|
|
#
|
2015-04-15 20:56:25 +00:00
|
|
|
# http://www.w3.org/TR/html/syntax.html#the-doctype
|
2014-05-06 22:50:34 +00:00
|
|
|
#
|
|
|
|
# These rules support the 3 flavours of doctypes:
|
|
|
|
#
|
|
|
|
# 1. Normal doctypes, as introduced in the HTML5 specification.
|
|
|
|
# 2. Deprecated doctypes, the more verbose ones used prior to HTML5.
|
|
|
|
# 3. Legacy doctypes
|
|
|
|
#
|
2015-04-15 18:22:14 +00:00
|
|
|
doctype_start = '<!DOCTYPE'i (whitespace_or_newline+ $count_newlines);
|
2014-05-06 22:50:34 +00:00
|
|
|
|
|
|
|
action start_doctype {
|
2014-11-21 00:37:33 +00:00
|
|
|
callback_simple(id_on_doctype_start);
|
2015-04-15 18:22:14 +00:00
|
|
|
|
|
|
|
if ( lines > 0 )
|
|
|
|
{
|
|
|
|
advance_line(lines);
|
|
|
|
|
|
|
|
lines = 0;
|
|
|
|
}
|
|
|
|
|
2014-05-20 22:08:48 +00:00
|
|
|
fnext doctype;
|
2014-05-06 22:50:34 +00:00
|
|
|
}
|
|
|
|
|
2014-11-18 19:02:55 +00:00
|
|
|
# Machine for processing inline rules of a doctype.
|
|
|
|
doctype_inline := |*
|
|
|
|
^']'* $count_newlines => {
|
2014-11-21 00:37:33 +00:00
|
|
|
callback(id_on_doctype_inline, data, encoding, ts, te);
|
2014-11-18 19:02:55 +00:00
|
|
|
|
|
|
|
if ( lines > 0 )
|
|
|
|
{
|
|
|
|
advance_line(lines);
|
|
|
|
|
|
|
|
lines = 0;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
']' => { fnext doctype; };
|
|
|
|
*|;
|
|
|
|
|
2014-05-06 22:50:34 +00:00
|
|
|
# Machine for processing doctypes. Doctype values such as the public
|
|
|
|
# and system IDs are treated as T_STRING tokens.
|
|
|
|
doctype := |*
|
|
|
|
'PUBLIC' | 'SYSTEM' => {
|
2014-11-21 00:37:33 +00:00
|
|
|
callback(id_on_doctype_type, data, encoding, ts, te);
|
2014-05-06 22:50:34 +00:00
|
|
|
};
|
|
|
|
|
2014-11-18 19:02:55 +00:00
|
|
|
# Starts a set of inline doctype rules.
|
|
|
|
'[' => { fnext doctype_inline; };
|
2014-05-09 22:28:11 +00:00
|
|
|
|
2014-05-06 22:50:34 +00:00
|
|
|
# Lex the public/system IDs as regular strings.
|
2014-10-26 10:39:56 +00:00
|
|
|
squote => start_string_squote;
|
|
|
|
dquote => start_string_dquote;
|
2014-05-06 22:50:34 +00:00
|
|
|
|
|
|
|
identifier => {
|
2014-11-21 00:37:33 +00:00
|
|
|
callback(id_on_doctype_name, data, encoding, ts, te);
|
2014-05-06 22:50:34 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
'>' => {
|
2014-11-21 00:37:33 +00:00
|
|
|
callback_simple(id_on_doctype_end);
|
2014-05-20 22:08:48 +00:00
|
|
|
fnext main;
|
2014-05-06 22:50:34 +00:00
|
|
|
};
|
2015-04-15 18:22:14 +00:00
|
|
|
|
|
|
|
newline => advance_newline;
|
|
|
|
|
|
|
|
whitespace;
|
2014-05-06 22:50:34 +00:00
|
|
|
*|;
|
|
|
|
|
|
|
|
# XML declaration tags
|
|
|
|
#
|
|
|
|
# http://www.w3.org/TR/REC-xml/#sec-prolog-dtd
|
|
|
|
#
|
|
|
|
xml_decl_start = '<?xml';
|
|
|
|
xml_decl_end = '?>';
|
|
|
|
|
|
|
|
action start_xml_decl {
|
2014-11-21 00:37:33 +00:00
|
|
|
callback_simple(id_on_xml_decl_start);
|
2014-05-20 22:08:48 +00:00
|
|
|
fnext xml_decl;
|
2014-05-06 22:50:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
# Machine that processes the contents of an XML declaration tag.
|
|
|
|
xml_decl := |*
|
|
|
|
xml_decl_end => {
|
2015-04-14 22:22:58 +00:00
|
|
|
if ( lines > 0 )
|
|
|
|
{
|
|
|
|
advance_line(lines);
|
|
|
|
|
|
|
|
lines = 0;
|
|
|
|
}
|
|
|
|
|
2014-11-21 00:37:33 +00:00
|
|
|
callback_simple(id_on_xml_decl_end);
|
2015-04-14 22:22:58 +00:00
|
|
|
|
2014-05-20 22:08:48 +00:00
|
|
|
fnext main;
|
2014-05-06 22:50:34 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
# Attributes and their values (e.g. version="1.0").
|
2014-07-20 05:29:37 +00:00
|
|
|
identifier => {
|
2015-04-14 22:22:58 +00:00
|
|
|
if ( lines > 0 )
|
|
|
|
{
|
|
|
|
advance_line(lines);
|
|
|
|
|
|
|
|
lines = 0;
|
|
|
|
}
|
|
|
|
|
2014-11-21 00:37:33 +00:00
|
|
|
callback(id_on_attribute, data, encoding, ts, te);
|
2014-05-06 22:50:34 +00:00
|
|
|
};
|
|
|
|
|
2014-10-26 10:39:56 +00:00
|
|
|
squote => start_string_squote;
|
|
|
|
dquote => start_string_dquote;
|
2014-05-06 22:50:34 +00:00
|
|
|
|
2015-04-14 22:22:58 +00:00
|
|
|
any $count_newlines;
|
2014-05-06 22:50:34 +00:00
|
|
|
*|;
|
|
|
|
|
|
|
|
# Elements
|
|
|
|
#
|
2015-04-15 20:56:25 +00:00
|
|
|
# http://www.w3.org/TR/html/syntax.html#syntax-elements
|
2014-05-06 22:50:34 +00:00
|
|
|
#
|
2014-05-20 22:21:21 +00:00
|
|
|
# Lexing of elements is broken up into different machines that handle the
|
|
|
|
# name/namespace, contents of the open tag and the body of an element. The
|
|
|
|
# body of an element is lexed using the `main` machine.
|
|
|
|
#
|
2014-09-02 20:50:21 +00:00
|
|
|
|
2014-09-02 22:51:13 +00:00
|
|
|
element_start = '<' ident_char;
|
|
|
|
element_end = '</' identifier (':' identifier)* '>';
|
2014-09-02 20:50:21 +00:00
|
|
|
|
2014-05-06 22:50:34 +00:00
|
|
|
action start_element {
|
2014-11-21 00:37:33 +00:00
|
|
|
callback_simple(id_on_element_start);
|
2014-09-02 22:51:13 +00:00
|
|
|
fhold;
|
2014-05-20 22:11:39 +00:00
|
|
|
fnext element_name;
|
2014-05-06 22:50:34 +00:00
|
|
|
}
|
|
|
|
|
2014-09-02 22:51:13 +00:00
|
|
|
action close_element {
|
2014-11-21 00:37:33 +00:00
|
|
|
callback_simple(id_on_element_end);
|
2014-09-02 22:51:13 +00:00
|
|
|
}
|
|
|
|
|
2014-05-15 08:22:05 +00:00
|
|
|
# Machine used for lexing the name/namespace of an element.
|
|
|
|
element_name := |*
|
|
|
|
identifier ':' => {
|
2014-11-21 00:37:33 +00:00
|
|
|
callback(id_on_element_ns, data, encoding, ts, te - 1);
|
2014-05-15 08:22:05 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
identifier => {
|
2014-11-21 00:37:33 +00:00
|
|
|
callback(id_on_element_name, data, encoding, ts, te);
|
2014-05-20 22:08:48 +00:00
|
|
|
fnext element_head;
|
2014-05-15 08:22:05 +00:00
|
|
|
};
|
|
|
|
*|;
|
2014-05-06 22:50:34 +00:00
|
|
|
|
2015-04-14 23:23:46 +00:00
|
|
|
# Characters that can be used for unquoted HTML attribute values.
|
|
|
|
# See https://html.spec.whatwg.org/multipage/introduction.html#intro-early-example
|
|
|
|
# for more info.
|
|
|
|
html_unquoted_value = ^(
|
2015-04-15 18:22:14 +00:00
|
|
|
squote | dquote | '`' | '=' | '<' | '>' | whitespace_or_newline
|
2015-04-14 23:23:46 +00:00
|
|
|
)+;
|
|
|
|
|
|
|
|
# Machine used for processing HTML attribute values.
|
|
|
|
html_attribute_value := |*
|
2015-04-14 23:47:08 +00:00
|
|
|
squote | dquote => {
|
|
|
|
fhold;
|
2015-04-14 23:50:42 +00:00
|
|
|
fnext xml_attribute_value;
|
2015-04-14 23:47:08 +00:00
|
|
|
};
|
2015-04-14 23:23:46 +00:00
|
|
|
|
|
|
|
# Unquoted attribute values are lexed as if they were single quoted
|
|
|
|
# strings.
|
|
|
|
html_unquoted_value => {
|
|
|
|
callback_simple(id_on_string_squote);
|
|
|
|
|
|
|
|
callback(id_on_string_body, data, encoding, ts, te);
|
|
|
|
|
|
|
|
callback_simple(id_on_string_squote);
|
|
|
|
};
|
|
|
|
|
2015-04-15 20:33:53 +00:00
|
|
|
any => hold_and_return;
|
2015-04-14 23:47:08 +00:00
|
|
|
*|;
|
|
|
|
|
2015-04-14 23:23:46 +00:00
|
|
|
# Machine used for processing XML attribute values.
|
|
|
|
xml_attribute_value := |*
|
2015-04-15 20:33:53 +00:00
|
|
|
# The following two actions use "fnext" instead of "fcall". Combined
|
|
|
|
# with "element_head" using "fcall" to jump to this machine this means
|
|
|
|
# we can return back to "element_head" after processing a single string.
|
|
|
|
squote => {
|
|
|
|
callback_simple(id_on_string_squote);
|
|
|
|
|
|
|
|
fnext string_squote;
|
|
|
|
};
|
|
|
|
|
|
|
|
dquote => {
|
|
|
|
callback_simple(id_on_string_dquote);
|
|
|
|
|
|
|
|
fnext string_dquote;
|
|
|
|
};
|
|
|
|
|
|
|
|
any => hold_and_return;
|
2015-04-14 23:23:46 +00:00
|
|
|
*|;
|
|
|
|
|
2014-05-20 22:21:21 +00:00
|
|
|
# Machine used for processing the contents of an element's starting tag.
|
|
|
|
# This includes the name, namespace and attributes.
|
2014-05-06 22:50:34 +00:00
|
|
|
element_head := |*
|
2015-04-15 18:22:14 +00:00
|
|
|
newline => advance_newline;
|
2014-05-06 22:50:34 +00:00
|
|
|
|
2014-07-20 05:29:37 +00:00
|
|
|
# Attribute names and namespaces.
|
|
|
|
identifier ':' => {
|
2014-11-21 00:37:33 +00:00
|
|
|
callback(id_on_attribute_ns, data, encoding, ts, te - 1);
|
2014-07-20 05:29:37 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
identifier => {
|
2014-11-21 00:37:33 +00:00
|
|
|
callback(id_on_attribute, data, encoding, ts, te);
|
2014-05-06 22:50:34 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
# Attribute values.
|
2015-04-14 23:23:46 +00:00
|
|
|
'=' => {
|
|
|
|
if ( html_p )
|
|
|
|
{
|
2015-04-15 20:33:53 +00:00
|
|
|
fcall html_attribute_value;
|
2015-04-14 23:23:46 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2015-04-15 20:33:53 +00:00
|
|
|
fcall xml_attribute_value;
|
2015-04-14 23:23:46 +00:00
|
|
|
}
|
|
|
|
};
|
2014-05-06 22:50:34 +00:00
|
|
|
|
2014-05-20 22:04:53 +00:00
|
|
|
# We're done with the open tag of the element.
|
|
|
|
'>' => {
|
2014-11-21 00:37:33 +00:00
|
|
|
callback_simple(id_on_element_open_end);
|
2015-03-02 15:20:54 +00:00
|
|
|
|
2015-03-03 15:28:05 +00:00
|
|
|
if ( literal_html_element_p() )
|
2015-03-02 15:20:54 +00:00
|
|
|
{
|
2015-03-03 15:28:05 +00:00
|
|
|
fnext literal_html_element;
|
2015-03-02 15:20:54 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
fnext main;
|
|
|
|
}
|
2014-05-20 22:04:53 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
# Self closing tags.
|
|
|
|
'/>' => {
|
2014-11-21 00:37:33 +00:00
|
|
|
callback_simple(id_on_element_end);
|
2014-05-20 22:08:48 +00:00
|
|
|
fnext main;
|
2014-05-06 22:50:34 +00:00
|
|
|
};
|
2015-04-15 20:33:53 +00:00
|
|
|
|
|
|
|
any;
|
2014-05-06 22:50:34 +00:00
|
|
|
*|;
|
|
|
|
|
2014-09-02 22:51:13 +00:00
|
|
|
# Text
|
|
|
|
#
|
|
|
|
# http://www.w3.org/TR/xml/#syntax
|
2015-04-15 20:56:25 +00:00
|
|
|
# http://www.w3.org/TR/html/syntax.html#text
|
2014-09-02 22:51:13 +00:00
|
|
|
#
|
|
|
|
# Text content is everything leading up to certain special tags such as "</"
|
|
|
|
# and "<?".
|
|
|
|
|
|
|
|
action start_text {
|
|
|
|
fhold;
|
|
|
|
fnext text;
|
|
|
|
}
|
|
|
|
|
|
|
|
# These characters terminate a T_TEXT sequence and instruct Ragel to jump
|
|
|
|
# back to the main machine.
|
|
|
|
#
|
|
|
|
# Note that this only works if each sequence is exactly 2 characters
|
|
|
|
# long. Because of this "<!" is used instead of "<!--".
|
|
|
|
|
|
|
|
terminate_text = '</' | '<!' | '<?' | element_start;
|
2014-09-25 20:49:11 +00:00
|
|
|
allowed_text = (any* -- terminate_text) $count_newlines;
|
2014-09-02 22:51:13 +00:00
|
|
|
|
|
|
|
text := |*
|
2014-09-25 20:49:11 +00:00
|
|
|
terminate_text | allowed_text => {
|
2014-11-21 00:37:33 +00:00
|
|
|
callback(id_on_text, data, encoding, ts, te);
|
2014-09-15 15:20:06 +00:00
|
|
|
|
2014-09-25 20:49:11 +00:00
|
|
|
if ( lines > 0 )
|
|
|
|
{
|
|
|
|
advance_line(lines);
|
|
|
|
|
|
|
|
lines = 0;
|
|
|
|
}
|
|
|
|
|
2014-09-15 15:20:06 +00:00
|
|
|
fnext main;
|
|
|
|
};
|
|
|
|
|
2014-09-02 22:51:13 +00:00
|
|
|
# Text followed by a special tag, such as "foo<!--"
|
2014-09-23 20:58:20 +00:00
|
|
|
allowed_text %{ mark = p; } terminate_text => {
|
2014-11-21 00:37:33 +00:00
|
|
|
callback(id_on_text, data, encoding, ts, mark);
|
2014-09-02 22:51:13 +00:00
|
|
|
|
|
|
|
p = mark - 1;
|
|
|
|
mark = 0;
|
|
|
|
|
2014-09-25 20:49:11 +00:00
|
|
|
if ( lines > 0 )
|
|
|
|
{
|
|
|
|
advance_line(lines);
|
|
|
|
|
|
|
|
lines = 0;
|
|
|
|
}
|
2014-09-02 22:51:13 +00:00
|
|
|
|
|
|
|
fnext main;
|
|
|
|
};
|
|
|
|
*|;
|
|
|
|
|
2015-03-03 15:28:05 +00:00
|
|
|
# Certain tags in HTML can contain basically anything except for the literal
|
|
|
|
# closing tag. Two examples are script and style tags. As a result of this
|
|
|
|
# we can't use the regular text machine.
|
2015-03-04 10:44:31 +00:00
|
|
|
literal_html_closing_tags = '</script>' | '</style>';
|
|
|
|
literal_html_allowed = (any* -- literal_html_closing_tags) $count_newlines;
|
|
|
|
|
2015-03-03 15:28:05 +00:00
|
|
|
literal_html_element := |*
|
2015-03-04 10:44:31 +00:00
|
|
|
literal_html_allowed => {
|
|
|
|
callback(id_on_text, data, encoding, ts, te);
|
|
|
|
|
|
|
|
if ( lines > 0 )
|
|
|
|
{
|
|
|
|
advance_line(lines);
|
|
|
|
|
|
|
|
lines = 0;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
literal_html_allowed %{ mark = p; } literal_html_closing_tags => {
|
|
|
|
callback(id_on_text, data, encoding, ts, mark);
|
2015-03-02 15:20:54 +00:00
|
|
|
|
2015-03-04 10:44:31 +00:00
|
|
|
p = mark - 1;
|
2015-03-02 15:20:54 +00:00
|
|
|
mark = 0;
|
|
|
|
|
|
|
|
if ( lines > 0 )
|
|
|
|
{
|
|
|
|
advance_line(lines);
|
|
|
|
|
|
|
|
lines = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
fnext main;
|
|
|
|
};
|
|
|
|
*|;
|
|
|
|
|
2014-05-20 22:21:21 +00:00
|
|
|
# The main machine aka the entry point of Ragel.
|
2014-05-06 22:50:34 +00:00
|
|
|
main := |*
|
|
|
|
doctype_start => start_doctype;
|
|
|
|
xml_decl_start => start_xml_decl;
|
2015-04-14 21:11:22 +00:00
|
|
|
comment_start => start_comment;
|
2015-04-14 20:45:55 +00:00
|
|
|
cdata_start => start_cdata;
|
2014-08-15 20:04:45 +00:00
|
|
|
proc_ins_start => start_proc_ins;
|
2014-09-02 22:51:13 +00:00
|
|
|
element_start => start_element;
|
|
|
|
element_end => close_element;
|
|
|
|
any => start_text;
|
2014-05-06 22:50:34 +00:00
|
|
|
*|;
|
|
|
|
}%%
|