I'm converting the DOM tree to a special markup macro which will dynamically render the html tags to the DOM (browser window). With the help of the crate (sycamore = "0.8.2").
Sycamore is a reactive library for creating web apps in Rust and WebAssembly in part of the rendering processs,
The resulting macro will be in a format of:
node (attributes) {
node (attributes) {
"Text"
node (attributes) {
. . .
}
}
"Text"
}
Starting from the original html, permit me if it's allowed. I wanted to test the nesting on the longer html to ensure the result correctness .
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
<meta name="description" content="" />
</head>
<body>
<!-- Navigation-->
<nav class="navbar navbar-expand-lg navbar-light" id="mainNav">
<div class="container px-4 px-lg-5">
<a class="navbar-brand" href="index.html">Start Bootstrap</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarResponsive" aria-controls="navbarResponsive" aria-expanded="false" aria-label="Toggle navigation">
Menu
<i class="fas fa-bars"></i>
</button>
<div class="collapse navbar-collapse" id="navbarResponsive">
<ul class="navbar-nav ms-auto py-4 py-lg-0">
<li class="nav-item"><a class="nav-link px-lg-3 py-3 py-lg-4" href="index.html">Home</a></li>
<li class="nav-item"><a class="nav-link px-lg-3 py-3 py-lg-4" href="about.html">About</a></li>
<li class="nav-item"><a class="nav-link px-lg-3 py-3 py-lg-4" href="post.html">Sample Post</a></li>
<li class="nav-item"><a class="nav-link px-lg-3 py-3 py-lg-4" href="contact.html">Contact</a></li>
</ul>
</div>
</div>
</nav>
<!-- Page Header-->
<header class="masthead" style="background-image: url('assets/img/home-bg.jpg')">
<div class="container position-relative px-4 px-lg-5">
<div class="row gx-4 gx-lg-5 justify-content-center">
<div class="col-md-10 col-lg-8 col-xl-7">
<div class="site-heading">
<h1>Clean Blog</h1>
<span class="subheading">A Blog Theme by Start Bootstrap</span>
</div>
</div>
</div>
</div>
</header>
<!-- Main Content-->
<div class="container px-4 px-lg-5">
<div class="row gx-4 gx-lg-5 justify-content-center">
<div class="col-md-10 col-lg-8 col-xl-7">
<!-- Post preview-->
<div class="post-preview">
<a href="post.html">
<h2 class="post-title">Man must explore, and this is exploration at its greatest</h2>
<h3 class="post-subtitle">Problems look mighty small from 150 miles up</h3>
</a>
<p class="post-meta">
Posted by
<a href="#!">Start Bootstrap</a>
on September 24, 2023
</p>
</div>
<hr class="my-4" />
<!-- Post preview-->
<div class="post-preview">
<a href="post.html">
<h2 class="post-title">Science has not yet mastered prophecy</h2>
<h3 class="post-subtitle">We predict too much for the next year and yet far too little for the next ten.</h3>
</a>
<p class="post-meta">
Posted by
<a href="#!">Start Bootstrap</a>
on August 24, 2023
</p>
</div>
<!-- Divider-->
<hr class="my-4" />
<!-- Post preview-->
<div class="post-preview">
<a href="post.html">
<h2 class="post-title">Failure is not an option</h2>
<h3 class="post-subtitle">Many say exploration is part of our destiny, but it’s actually our duty to future generations.</h3>
</a>
<p class="post-meta">
Posted by
<a href="#!">Start Bootstrap</a>
on July 8, 2023
</p>
</div>
<!-- Divider-->
<hr class="my-4" />
<!-- Pager-->
<div class="d-flex justify-content-end mb-4"><a class="btn btn-primary text-uppercase" href="#!">Older Posts →</a></div>
</div>
</div>
</div>
<!-- Bootstrap core JS-->
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script>
<!-- Core theme JS-->
<script src="js/scripts.js"></script>
</body>
</html>
After building the recursive function and testing, I did not get the desired nesting output:
As you can see, some of the tags by their braces are not properly nested.
the nested head tag omitted the link tags, the nested body omitted the rest of the html document.
To see how the braces match, in your code editor hover or click at the beginning of the opening brace and watch where the closing brace highlights.
Running `target/debug/sytree`
html(lang="en") {
head() {
meta(charset="utf-8") {
}
meta(content="width=device-width, initial-scale=1, shrink-to-fit=no" name="viewport") {
}
meta(content="" name="description") {
}
meta(name="author" content="") {
}
title() {
"Clean Blog - Start Bootstrap Theme"
}
link(rel="icon" type="image/x-icon" href="assets/favicon.ico") {
}
script(src="https://use.fontawesome.com/releases/v6.3.0/js/all.js" crossorigin="anonymous") {
}
link(rel="stylesheet" href="https://fonts.googleapis.com/css?family=Lora:400,700,400italic,700italic" type="te
xt/css") {
}
link(type="text/css" href="https://fonts.googleapis.com/css?family=Open+Sans:300italic,400italic,600italic,700
italic,800italic,400,300,600,700,800" rel="stylesheet") {
}
link(rel="stylesheet" href="css/styles.css") {
}
}
body() {
nav(class="navbar navbar-expand-lg navbar-light" id="mainNav") {
div(class="container px-4 px-lg-5") {
a(class="navbar-brand" href="index.html") {
"Start Bootstrap"
}
button(class="navbar-toggler" data-bs-toggle="collapse" data-bs-target="#navbarResponsive" aria-controls="
navbarResponsive" aria-expanded="false" aria-label="Toggle navigation" type="button") {
"Menu"
i(class="fas fa-bars") {
}
}
div(id="navbarResponsive" class="collapse navbar-collapse") {
ul(class="navbar-nav ms-auto py-4 py-lg-0") {
li(class="nav-item") {
a(href="index.html" class="nav-link px-lg-3 py-3 py-lg-4") {
"Home"
}
}
li(class="nav-item") {
a(class="nav-link px-lg-3 py-3 py-lg-4" href="about.html") {
"About"
}
}
li(class="nav-item") {
a(href="post.html" class="nav-link px-lg-3 py-3 py-lg-4") {
"Sample Post"
}
}
li(class="nav-item") {
a(href="contact.html" class="nav-link px-lg-3 py-3 py-lg-4") {
"Contact"
}
}
}
}
}
}
header(style="background-image: url('assets/img/home-bg.jpg')" class="masthead") {
div(class="container position-relative px-4 px-lg-5") {
div(class="row gx-4 gx-lg-5 justify-content-center") {
div(class="col-md-10 col-lg-8 col-xl-7") {
div(class="site-heading") {
h1() {
"Clean Blog"
}
span(class="subheading") {
"A Blog Theme by Start Bootstrap"
}
}
}
}
}
}
div(class="container px-4 px-lg-5") {
div(class="row gx-4 gx-lg-5 justify-content-center") {
div(class="col-md-10 col-lg-8 col-xl-7") {
div(class="post-preview") {
a(href="post.html") {
h2(class="post-title") {
"Man must explore, and this is exploration at its greatest"
}
h3(class="post-subtitle") {
"Problems look mighty small from 150 miles up"
}
}
p(class="post-meta") {
"Posted by"
a(href="#!") {
"Start Bootstrap"
}
"on September 24, 2023"
}
}
hr(class="my-4") {
}
div(class="post-preview") {
a(href="post.html") {
h2(class="post-title") {
"I believe every human has a finite number of heartbeats. I don't intend to waste any of mine."
}
}
p(class="post-meta") {
"Posted by"
a(href="#!") {
"Start Bootstrap"
}
"on September 18, 2023"
}
}
hr(class="my-4") {
}
div(class="post-preview") {
a(href="post.html") {
h2(class="post-title") {
"Science has not yet mastered prophecy"
}
h3(class="post-subtitle") {
"We predict too much for the next year and yet far too little for the next ten."
}
}
p(class="post-meta") {
"Posted by"
a(href="#!") {
"Start Bootstrap"
}
"on August 24, 2023"
}
}
hr(class="my-4") {
}
div(class="post-preview") {
a(href="post.html") {
h2(class="post-title") {
"Failure is not an option"
}
h3(class="post-subtitle") {
"Many say exploration is part of our destiny, but it’s actually our duty to future generations."
}
}
p(class="post-meta") {
"Posted by"
a(href="#!") {
"Start Bootstrap"
}
"on July 8, 2023"
}
}
hr(class="my-4") {
}
div(class="d-flex justify-content-end mb-4") {
a(href="#!" class="btn btn-primary text-uppercase") {
"Older Posts →"
}
}
}
}
}
footer(class="border-top") {
div(class="container px-4 px-lg-5") {
div(class="row gx-4 gx-lg-5 justify-content-center") {
div(class="col-md-10 col-lg-8 col-xl-7") {
ul(class="list-inline text-center") {
li(class="list-inline-item") {
a(href="#!") {
span(class="fa-stack fa-lg") {
i(class="fas fa-circle fa-stack-2x") {
}
i(class="fab fa-twitter fa-stack-1x fa-inverse") {
}
}
}
}
li(class="list-inline-item") {
a(href="#!") {
span(class="fa-stack fa-lg") {
i(class="fas fa-circle fa-stack-2x") {
}
i(class="fab fa-facebook-f fa-stack-1x fa-inverse") {
}
}
}
}
li(class="list-inline-item") {
a(href="#!") {
span(class="fa-stack fa-lg") {
i(class="fas fa-circle fa-stack-2x") {
}
i(class="fab fa-github fa-stack-1x fa-inverse") {
}
}
}
}
}
div(class="small text-center text-muted fst-italic") {
"Copyright © Your Website 2023"
}
}
}
}
}
script(src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js") {
}
script(src="js/scripts.js") {
}
}
}
This is my current implementation.
extern crate scraper;
use scraper::{ElementRef, Html, Selector};
use std::fs;
fn format_attribute(key: &str, value: &str) -> String {
format!("{}=\"{}\"", key, value)
}
fn walk_tree(element: ElementRef, indent: usize) {
let name = element.value().name();
let attrs = element
.value()
.attrs()
.map(|(k, v)| format_attribute(k, v))
.collect::<Vec<_>>()
.join(" ");
println!("{}{}({}) {{", " ".repeat(indent), name, attrs); // Add an opening brace here
for child in element.children() {
match child.value() {
scraper::Node::Element(_) => {
let child_ref = ElementRef::wrap(child).unwrap();
walk_tree(child_ref, indent + 2);
}
scraper::Node::Text(text_node) => {
let trimmed_text = text_node.trim();
if !trimmed_text.is_empty() {
let txt = format!("{}\"{}\"", " ".repeat(indent + 2), trimmed_text);
println!("{}", txt); // Remove the closing brace here
}
}
_ => {}
}
}
println!("{}}}", " ".repeat(indent)); // Add a closing brace here
}
fn main() {
let html_file = fs::read_to_string("/home/afidegnum/Projects/Labs/Nvim/Syca/sytags/index.html")
.expect("Unable to read file");
let document = Html::parse_document(&html_file);
let body = document.root_element();
walk_tree(body, 0);
}
How do i adjust the opening and closing of the braces { and } in order to properly wrap the nested elements?