From a3434dd70c52017fd6e1595f7916721963e8e4e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn?= Date: Fri, 19 Nov 2021 20:36:48 +0000 Subject: [PATCH] HtmlNode.ToString(): fix self-closing tags on empty non-void elements Quoting from https://www.w3.org/TR/2011/WD-html-markup-20110113/syntax.html#void-element > The following is a complete list of the void elements in HTML: > area, base, br, col, command, embed, hr, img, input, keygen, link, > meta, param, source, track, wbr [...] > Void elements only have a start tag; end tags must not be specified > for void elements. > A non-void element must have an end tag, unless the subsection for > that element in the HTML elements section of this reference indicates > that its end tag can be omitted. --- src/Html/HtmlParser.fs | 19 +++++++++++-------- tests/FSharp.Data.Tests/HtmlParser.fs | 17 +++++++++++++++-- 2 files changed, 26 insertions(+), 10 deletions(-) diff --git a/src/Html/HtmlParser.fs b/src/Html/HtmlParser.fs index c41fcb7a8..dd4184054 100644 --- a/src/Html/HtmlParser.fs +++ b/src/Html/HtmlParser.fs @@ -93,14 +93,18 @@ type HtmlNode = static member NewCData content = HtmlCData(content) override x.ToString() = + let isVoidElement = + let set = + [| "area"; "base"; "br"; "col"; "command"; "embed"; "hr"; "img"; "input" + "keygen"; "link"; "meta"; "param"; "source"; "track"; "wbr" |] + |> Set.ofArray + fun name -> Set.contains name set let rec serialize (sb:StringBuilder) indentation canAddNewLine html = let append (str:string) = sb.Append str |> ignore let appendEndTag name = append "" - let shouldAppendEndTag name = - name = "textarea" let newLine plus = sb.AppendLine() |> ignore String(' ', indentation + plus) |> append @@ -117,12 +121,11 @@ type HtmlNode = append "=\"" append value append "\"" - if elements.IsEmpty then - if shouldAppendEndTag name then - append ">" - appendEndTag name - else - append " />" + if isVoidElement name then + append " />" + elif elements.IsEmpty then + append ">" + appendEndTag name else append ">" if not onlyText then diff --git a/tests/FSharp.Data.Tests/HtmlParser.fs b/tests/FSharp.Data.Tests/HtmlParser.fs index 359cdf175..8e4a5abca 100644 --- a/tests/FSharp.Data.Tests/HtmlParser.fs +++ b/tests/FSharp.Data.Tests/HtmlParser.fs @@ -647,6 +647,19 @@ let ``Renders textarea closing tag``() = result |> should equal """""" +[] +let ``Renders self-closing tag for void elements``() = + [ "area"; "base"; "br"; "col"; "command"; "embed"; "hr"; "img"; "input" + "keygen"; "link"; "meta"; "param"; "source"; "track"; "wbr" ] + |> List.iter (fun name -> + let html = HtmlNode.NewElement name |> string + html |> should equal $"<%s{name} />") + +[] +let ``Renders no self-closing tag for non-void elements``() = + let html = HtmlNode.NewElement "foo" |> string + html |> should equal "" + [] let ``Can handle CDATA blocks``() = let cData = """ @@ -911,9 +924,9 @@ let ``Parsing non-html content doesn't cause an infinite loop - Github-1264``() [] let ``Can handle incomplete tags at end of file without creating an infinite loop``() = let result = HtmlDocument.Parse """ should equal expected \ No newline at end of file + result |> should equal expected