HTML
facet-html parses and serializes HTML documents using Facet. Define your document structure with #[facet(html::element)] for child elements, #[facet(html::attribute)] for tag attributes, and #[facet(html::text)] for text content.
Parsing HTML
Simple Document
Parse a basic HTML document with head, body, and nested elements.
Target Type
/// A simple page structure with head and body.
# [ derive ( Facet )]
struct SimplePage {
# [ facet ( html :: element )]
head : Option < SimpleHead >,
# [ facet ( html :: element )]
body : Option < SimpleBody >,
}
# [ derive ( Facet )]
struct SimpleBody {
# [ facet ( html :: attribute )]
class : Option < String >,
# [ facet ( html :: elements )]
children : Vec < BodyElement >,
}
/// Elements that can appear in the body.
# [ derive ( Facet )]
# [ repr ( u8 )]
enum BodyElement {
H1 ( Heading ),
P ( Paragraph ),
Div ( DivElement ),
}
# [ derive ( Facet )]
struct DivElement {
# [ facet ( html :: attribute )]
id : Option < String >,
# [ facet ( html :: attribute )]
class : Option < String >,
# [ facet ( html :: text )]
content : String ,
}
# [ derive ( Facet )]
struct Paragraph {
# [ facet ( html :: attribute )]
class : Option < String >,
# [ facet ( html :: text )]
text : String ,
}
# [ derive ( Facet )]
struct Heading {
# [ facet ( html :: attribute )]
id : Option < String >,
# [ facet ( html :: text )]
text : String ,
}
# [ derive ( Facet )]
struct SimpleHead {
# [ facet ( html :: element )]
title : Option < SimpleTitle >,
}
# [ derive ( Facet )]
struct SimpleTitle {
# [ facet ( html :: text )]
text : String ,
}
HTML Input
html
< html >
< head >< title > My Page</ title ></ head >
< body class ="main ">
< h1 id ="header "> Welcome</ h1 >
< p > Hello, world!</ p >
</ body >
</ html >
Success
SimplePage {
head: Option::Some(SimpleHead {
title: Option::Some(SimpleTitle {
text: "My Page",
}),
}),
body: Option::Some(SimpleBody {
class: Option::Some("main"),
children: Vec<BodyElement>[],
}),
}
Nested Elements
Parse nested HTML elements into an enum-based content model.
Target Type
/// A simple page structure with head and body.
# [ derive ( Facet )]
struct SimplePage {
# [ facet ( html :: element )]
head : Option < SimpleHead >,
# [ facet ( html :: element )]
body : Option < SimpleBody >,
}
# [ derive ( Facet )]
struct SimpleBody {
# [ facet ( html :: attribute )]
class : Option < String >,
# [ facet ( html :: elements )]
children : Vec < BodyElement >,
}
/// Elements that can appear in the body.
# [ derive ( Facet )]
# [ repr ( u8 )]
enum BodyElement {
H1 ( Heading ),
P ( Paragraph ),
Div ( DivElement ),
}
# [ derive ( Facet )]
struct DivElement {
# [ facet ( html :: attribute )]
id : Option < String >,
# [ facet ( html :: attribute )]
class : Option < String >,
# [ facet ( html :: text )]
content : String ,
}
# [ derive ( Facet )]
struct Paragraph {
# [ facet ( html :: attribute )]
class : Option < String >,
# [ facet ( html :: text )]
text : String ,
}
# [ derive ( Facet )]
struct Heading {
# [ facet ( html :: attribute )]
id : Option < String >,
# [ facet ( html :: text )]
text : String ,
}
# [ derive ( Facet )]
struct SimpleHead {
# [ facet ( html :: element )]
title : Option < SimpleTitle >,
}
# [ derive ( Facet )]
struct SimpleTitle {
# [ facet ( html :: text )]
text : String ,
}
HTML Input
html
< html >
< body >
< div id ="container " class ="wrapper ">
< h1 > Title</ h1 >
< p class ="intro "> Introduction paragraph.</ p >
< div class ="content "> Main content here.</ div >
</ div >
</ body >
</ html >
Success
SimplePage {
head: Option::None,
body: Option::Some(SimpleBody {
class: Option::None,
children: Vec<BodyElement>[],
}),
}
Form Elements
Parse HTML form elements with their attributes.
Target Type
/// A form element with various input types.
# [ derive ( Facet )]
struct ContactForm {
# [ facet ( html :: attribute )]
action : Option < String >,
# [ facet ( html :: attribute )]
method : Option < String >,
# [ facet ( html :: elements )]
inputs : Vec < FormInput >,
}
# [ derive ( Facet )]
struct FormInput {
# [ facet ( html :: attribute )]
input_type : Option < String >,
# [ facet ( html :: attribute )]
name : Option < String >,
# [ facet ( html :: attribute )]
placeholder : Option < String >,
# [ facet ( html :: attribute )]
required : Option < String >,
}
HTML Input
html
< form action ="/submit " method ="post ">
< input type ="text " name ="username " placeholder ="Username " required />
< input type ="email " name ="email " placeholder ="Email " />
< input type ="submit " name ="submit " />
</ form >
Success
ContactForm {
action: Option::Some("/submit"),
method: Option::Some("post"),
inputs: Vec<FormInput> [
FormInput {
input_type: Option::Some("text"),
name: Option::Some("username"),
placeholder: Option::Some("Username"),
required: Option::Some(""),
},
FormInput {
input_type: Option::Some("email"),
name: Option::Some("email"),
placeholder: Option::Some("Email"),
required: Option::None,
},
FormInput {
input_type: Option::Some("submit"),
name: Option::Some("submit"),
placeholder: Option::None,
required: Option::None,
},
],
}
Serialization
Minified Output
Serialize to compact HTML without extra whitespace.
Target Type
# [ derive ( Facet )]
struct DivElement {
# [ facet ( html :: attribute )]
id : Option < String >,
# [ facet ( html :: attribute )]
class : Option < String >,
# [ facet ( html :: text )]
content : String ,
}
HTML Output
html
< divElement id ="main " class ="container "> Hello!</ divElement >
Pretty-Printed Output
Serialize with indentation for readability.
Target Type
/// A form element with various input types.
# [ derive ( Facet )]
struct ContactForm {
# [ facet ( html :: attribute )]
action : Option < String >,
# [ facet ( html :: attribute )]
method : Option < String >,
# [ facet ( html :: elements )]
inputs : Vec < FormInput >,
}
# [ derive ( Facet )]
struct FormInput {
# [ facet ( html :: attribute )]
input_type : Option < String >,
# [ facet ( html :: attribute )]
name : Option < String >,
# [ facet ( html :: attribute )]
placeholder : Option < String >,
# [ facet ( html :: attribute )]
required : Option < String >,
}
HTML Output
html
< form action ="/api/contact " method ="post ">< input type ="text " name ="name " placeholder ="Your name " required >< input type ="email " name ="email " placeholder ="your@email.com "></ form >
Advanced Features
Extra Attributes (data-, aria-)
Unknown attributes like data-* and aria-* are captured in the extra field via #[facet(flatten)].
Target Type
/// A div that captures extra attributes (data-*, aria-*, etc.)
# [ derive ( Facet )]
struct DivWithExtras {
# [ facet ( html :: attribute )]
id : Option < String >,
# [ facet ( html :: attribute )]
class : Option < String >,
/// Captures data-*, aria-*, and other unknown attributes
extra : BTreeMap < String , String >,
# [ facet ( html :: text )]
content : String ,
}
HTML Input
html
< div id ="widget " class ="card " data-user-id ="123 " data-theme ="dark " aria-label ="User Card "> Content</ div >
Success
DivWithExtras {
id: Option::Some("widget"),
class: Option::Some("card"),
extra: BTreeMap<String, String> [
"aria-label" => "User Card",
"data-theme" => "dark",
"data-user-id" => "123",
],
content: "Content",
}