ocsigen / tyxml

Build valid HTML and SVG documents
https://ocsigen.org/tyxml/
Other
166 stars 62 forks source link

Interpolating unsafe elements into a document via JSX can change surrounding HTML structure #292

Open cemerick opened 3 years ago

cemerick commented 3 years ago

I'm currently using Unsafe.data to bring known-good HTML fragments (produced by a reasonable markdown->HTML generator) into the tyxml world. AIUI, that should be okay, but perhaps the current issue demonstrates that it is not.

When Unsafe.data-produced content that contains a self-closed tag (e.g. <div/>) is interpolated into a JSX template, the structure surrounding that interpolation is changed. For example, interpolating the poison element as shown here yields an HTML document where the div containing "2" is pulled into its predecessor, so that both "1" and "2" are surrounded by a red border:

let greet = () => {
  let poison = Tyxml.Html.Unsafe.data("<div/>");
  <html>
    <head><title>"Home"</title></head>
    <body>
      <div style="border:solid red 1px">
        "1" poison
      </div>
      <div> "2" </div>
    </body>
  </html>
  }

A Dream playground example is available with this code already populated, demonstrating the problem: http://dream.as/XYZ68EQPDKVt

A quick side test of this using only tyxml (i.e. no jsx) yields the expected behaviour, so it seems the interpolation into jsx is the culprit somehow.

Drup commented 3 years ago

In general, it's better to debug these kind of things by looking at the emitted HTML before the browser result.

In this case, the emited HTML is:

<html><head><title>Home</title></head>
<body>
  <div style="border:solid red 1px">
    1
    <div/>
  </div>
  <div>2</div>
</body>
</html>

Which is what you wanted ... but also completely invalid HTML, and triggers the error recovery mode in the browser's HTML parsing, resulting in the wrong result you see. <div/> is not a thing in valid HTML. If you replace by <div></div>, you get what you want.