Expand description
Rust templating for XML-based formats (HTML, SVG, MathML) implemented on top
of [proc-macro::TokenStream
]s. Similar to JSX but for Rust (commonly named
RSX). The parsed result is a nested Node
structure, similar to the
browser DOM, where node name and value are syn expressions to support
building proc macros.
use std::convert::TryFrom;
use eyre::bail;
use quote::quote;
use rstml::{
node::{Node, NodeAttribute, NodeElement, NodeText},
parse2,
};
// Create HTML `TokenStream`.
let tokens = quote! { <hello world>"hi"</hello> };
// Parse the tokens into a tree of `Node`s.
let nodes = parse2(tokens)?;
// Extract some specific nodes from the tree.
let Node::Element(element) = &nodes[0] else {
bail!("element")
};
let NodeAttribute::Attribute(attribute) = &element.attributes()[0] else {
bail!("attribute")
};
let Node::Text(text) = &element.children[0] else {
bail!("text")
};
// Work with the nodes.
assert_eq!(element.name().to_string(), "hello");
assert_eq!(attribute.key.to_string(), "world");
assert_eq!(text.value_string(), "hi");
You might want to check out the html-to-string-macro example as well.
Features
-
Not opinionated
Every tag or attribute name is valid
<hello world />
-
Text nodes
<div>"String literal"</div>
-
Unquoted text nodes
Unquoted text is supported with few limitations:
- Only valid Rust TokenStream can be unquoted text (no single quote text is supported, no unclosed braces, etc.)
- Unquoted text not always can save spaces. It uses
Span::source_text
andSpan::join
to retrive info about spaces, and it is not always available. - Quoted text near unquoted treated as diferent Node, end library user should decide whenever to preserve quotation.
<div> Some string that is valid rust token stream </div>
-
Node names separated by dash, colon or double colon
<tag-name some:attribute-key="value" /> <tag::name attribute::key="value" />
-
Node names with reserved keywords
<input type="submit" />
-
Doctypes, Comments and Fragments
<!DOCTYPE html> <!-- "comment" --> <></>
-
Braced blocks are parsed as arbitrary Rust code
<{ let block = "in node name position"; } /> <div>{ let block = "in node position"; }</div> <div { let block = "in attribute position"; } /> <div key={ let block = "in attribute value position"; } />
-
Attribute values can be any valid syn expression without requiring braces
<div key=some::value() />
-
Helpful error reporting out of the box
error: open tag has no corresponding close tag and is not self-closing --> examples/html-to-string-macro/tests/lib.rs:5:24 | 5 | html_to_string! { <div> }; | ^^^
-
Possibility to get the span for a whole node
This can be used to improve error reporting, e.g.
error: Invalid element
--> examples/src/main.rs:14:13
|
14 | / <div>
15 | | "invalid node for some consumer specific reason"
16 | | </div>
| |__________________^
- Recoverable parser
Can parse html with multiple mistakes. As result library user get array of errors that can be reported, and tree of nodes that was parsed.
<div hello={world.} /> <!-- dot after world is invalid syn expression -->
<>
<div>"1"</x> <!-- incorrect closed tag -->
<div>"2"</div>
<div>"3"</div>
<div {"some-attribute-from-rust-block"}/>
</>
Using this feature one can write macro in IDE friendly way. This macro will work faster (because on invalid syntax it change output slightly, instead of removing it completely, so IDE can check diff quicly). And give completion (goto definition, and other semantic related feature) more often.
-
Customization
A
ParserConfig
to customize parsing behavior is available, so if you have slightly different requirements for parsing and it’s not yet customizable feel free to open an issue or pull request to extend the configuration.One highlight with regards to customization is the
transform_block
configuration, which takes a closure that receives raw block content asParseStream
and lets you optionally convert it to aTokenStream
. That makes it possible to have custom syntax in blocks. More details in #9
Re-exports
pub use node::atoms;
Modules
- Tree of nodes.
- Recoverable parser helper module. Contains trait and types that are using during implementation of parsing with recovery after semantic errors.
Structs
- Primary library interface to RSX Parser
- Configures the
Parser
behavior
Enums
- Result of parsing.
Functions
- Parse the given
proc-macro::TokenStream
into aNode
tree. - Parse the given
proc-macro2::TokenStream
into aNode
tree. - parse2_with_configDeprecated
- parse_with_configDeprecated