Permalink
Browse files

[feature] Parser: html5 void elements (without close tag) now supported

  • Loading branch information...
cedricss committed Apr 24, 2012
1 parent a2e8fe7 commit 425ef5fec330a4fb180b22e86207e7f9678d8b7f
@@ -0,0 +1,22 @@
+(*
+ Copyright © 2011 MLstate
+
+ This file is part of OPA.
+
+ OPA is free software: you can redistribute it and/or modify it under the
+ terms of the GNU Affero General Public License, version 3, as published by
+ the Free Software Foundation.
+
+ OPA is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
+ more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with OPA. If not, see <http://www.gnu.org/licenses/>.
+*)
+##
+## @author Cedric Soulas
+##
+
+void_element <- "htmlarea" / "base" / "br" / "col" / "command" / "embed" / "hr" / "img" / "input" / "keygen" / "link" / "meta" / "param" / "source" / "track" / "wbr"
@@ -1295,6 +1295,17 @@ let tag_mismatch ((ns1,_annot), (tag1,{QmlLoc.pos = pos1})) ((ns2,_annot), (tag2
_annot
else ()
+let nochild_elem nstag close_tag has_children create =
+ let ((ns1,_annot),(tag1,{QmlLoc.pos = pos1})) = nstag in
+ let ((ns2,_),(tag2,_)) = close_tag in
+ if tag1 = tag2 && ns1 = ns2 then begin
+ if not has_children then Some (create ())
+ else error1 (sprintf "and %s\n <%s> is a void element: it can't have children"
+ (FilePos.to_string pos1)
+ (nstag_to_string ns1 tag1))
+ _annot
+ end else None
+
let add_arg src ((prefix,_),name) value =
let old = arg_default src in
{ old with args = (prefix, fst name, Option.default (unc2 string name) value) :: old.args }
@@ -446,6 +446,7 @@ val create_element :
(string, 'a) expr list ->
(string, 'a) expr
val tag_mismatch : (string * annot) * (string * annot) -> (string * annot) * (string * annot) -> unit
+val nochild_elem : (string * annot) * (string * annot) -> (string * annot) * (string * annot) -> bool -> (unit -> 'b) -> 'b option
val add_arg :
'a dom_tag_args option * annot ->
(string * annot) * (string * annot) ->
@@ -23,6 +23,7 @@
let deco rule = (=Opa_parser.careful_deco(rule));
pos <- Opa_parser.pos;
read htmlentities.trx
+read html5.trx
#####################################################################################
## HTML TEXT ########################################################################
@@ -84,6 +85,7 @@ htmltext <- htmlchars+:s {{ concat_xml_text s }}
deco_sname = deco sname;
deco_ename = deco ename;
deco_tname = deco tname;
+deco_html5voidtname = deco Html5.void_element;
deco_htmltext = deco htmltext;
deco_svalue = deco svalue;
deco_spaces = deco spaces;
@@ -96,9 +98,15 @@ close_sign <- spacing ">"
autoclose <- spacing "/" close_sign
begin_open_tag <- open_sign namespace:ns deco_tname:tag spacing {{ push_tag (undecorate tag); (ns, tag) }}
+begin_open_html5_void_tag <- open_sign namespace:ns deco_html5voidtname:tag spacing {{ push_tag (undecorate tag); (ns, tag) }}
+
(* FIXME: factorisation of open_tag and autoclose_tag *)
/** xml open tag **/
open_tag <- begin_open_tag:nstag args_option:args close_sign {{ (nstag, arg_default args) }}
+
+/** html5 open void tag **/
+open_html5_void_tag <- begin_open_html5_void_tag:nstag args_option:args close_sign {{ (nstag, arg_default args) }}
+
/** xml close tag **/
close_tag <- open_sign "/" spacing namespace:ns deco_tname:tag close_sign {{ ignore (pop_tag()); (ns, tag) }}
@@ -113,6 +121,10 @@ close_frag <- open_sign "/" spacing close_sign
close_tag_or_frag <- close_tag:t {{ Some t }}
/ close_frag {{ None }}
+(** For html5 void element, end tags can be omitted *)
+/** html5 void element without close tag **/
+noclose_elem <- begin_open_html5_void_tag:nstag args_option:args spacing close_sign {{ ignore (pop_tag()); (nstag, arg_default args) }}
+
#####################################################################################
## XHTML TYPES ######################################################################
#####################################################################################
@@ -123,20 +135,34 @@ xhtml_text <- deco_htmltext:v {{ create_textnode v }}
/ xhtml_tag / xhtml_text / xhtml_fragment
/ opa_expr:e {{ wrap_e magic_to_xml e }}
+(** We consider void elements as those define in the html5 spec
+ Those elements can be closed, but in this case: it has no child and close tag is not a close_frag *)
+/** void element with close tag and no child **/
+nochild_elem <- open_html5_void_tag:open_tag has_children_nodes:has_children close_tag:close_tag
+ {| let nstag, args = open_tag in
+ nochild_elem nstag close_tag has_children (fun _ -> (create_element nstag args [])) |}
+
;/** xml tag **/
xhtml_tag <-
/ comment spacing xhtml_tag:tag {{ tag }}
/ autoclose_tag:t {{ let nstag,args = t in create_element nstag args [] }}
+ / nochild_elem:e {{ e }}
+ / noclose_elem:t {{ let nstag,args = t in create_element nstag args [] }}
/ open_tag:open_tag just_xhtml_nodes:children close_tag_or_frag:close_tag
{{ let nstag, args = open_tag in
Option.iter (tag_mismatch nstag) close_tag;
create_element nstag args children }}
+
;/** xml fragment **/
xhtml_fragment <- open_frag xhtml_nodes:p close_frag {{ let (l,label) = p in create_fragment l label }}
;xhtml_nodes = deco just_xhtml_nodes
;just_xhtml_nodes <- xhtml_node*
+has_children_nodes <-
+ / Opa_lexer.strict_spacing !(xhtml_node+) {{ false }}
+ / xhtml_node+ {{ true }}
+ / '' {{ false }}
;xhtml_empty_frag = deco just_xhtml_empty_frag
;just_xhtml_empty_frag <- open_frag spacing close_frag

0 comments on commit 425ef5f

Please sign in to comment.