Compare HTML Fragments in Rust to See if They Match

August 2026

I'm working on extracting NeoDoc from my static site generator to pitch the format as an option for the Atmosphere of AT Proto. Part of that process is making an explicit spec for HTML output. The goal being to avoid a Markdown type situation where different parsers have different features that produces different outputs from the same input.

Validating the output is a little tricky. The simplest way would be to just compare to strings.

is
<strong>test</strong>
the same as:
<strong>test</strong>
yes? you're good

The problem is whitespace. Take these two snippets for example:

<div>
<strong>test</strong>
</div>

and

<div>
  <strong>test</strong>
</div>

The only difference in them is the strong tag has a couple spaces in front of it in the second sample.

Both samples produce the exact same thing in the browser. And, for testing purposes, they should be considered as matching.

But, thanks to the whitespace, the strings are different. So, the test would fail.

I've done simple testing before where I just yoinked all the spaces to collapse everything. That works great, as long as you don't need to run tests that confirm what space that should show up does. NeoDoc has some of those tests.

I'm using a rust crate called scraper to work around that. It parses HTML that can be compared more abstractly.

This is how I'm using it:

use scraper::{Html, Selector};

fn main() {
  let left = r#"
<h1 class="red" id="ping">Hello World</h1>
"#;

  let right = r#"
<h1 id="ping" 
    class="red">Hello World</h1>
"#;

  println!(
    "Is Same HTML: {}",
    is_same_html(left, right),
  );
}

pub fn is_same_html(
  left_input: &str,
  right_input: &str,
) -> bool {
  let selector = Selector::parse("*").unwrap();
  let left_frag = Html::parse_fragment(left_input);
  let right_frag = Html::parse_fragment(right_input);
  let left =
    left_frag.select(&selector).next().unwrap();
  let right =
    right_frag.select(&selector).next().unwrap();
  left.html() == right.html()
}
with this Cargo.toml:
[package]
name = "compare-html"
version = "0.1.0"
edition = "2024"

[dependencies]
scraper = { version = "0.27.0" }
which produces this:
Is Same HTML: true
The whitespace in the middle of the `h1` element gets disregarded. So does the order of the attributes themselves. Even though the order of the arguments is `class, id` in the `left` variable and `id, class` in the `right` the HTML still matches. This is exactly what I'm looking for since those two samples rendered the same even though their string representations are different.

Test solution acquired. Back to parsing,

-a

Endnotes