Repository files navigation

tl

tl is a fast HTML parser written in pure Rust.

This crate (currently) does not strictly follow the full specification of the HTML standard, however this usually is not a problem for most use cases. This crate generally attempts to support most "sane" HTML. Not being limited by a specification allows for more optimization opportunities. If you need a parser that can (very quickly) parse the typical HTML document and you need a simple API to work with the DOM, give this crate a try.

If you need a parser that closely follows the standard, consider using html5ever, lol-html, or html5gum.

Usage

Add tl to your dependencies.

[dependencies]
tl = "0.7.8"# or, with explicit SIMD support# (requires a nightly compiler!)tl = { version = "0.7.8", features = ["simd"] }

The main function is tl::parse(). It accepts an HTML source code string and parses it. It is important to note that tl currently silently ignores tags that are invalid, sort of like browsers do. Sometimes, this means that large chunks of the HTML document do not appear in the resulting tree.

let dom = tl::parse(r#"<p id="text">Hello</p>"#, tl::ParserOptions::default()).unwrap();let parser = dom.parser();let element = dom.get_element_by_id("text").expect("Failed to find element").get(parser).unwrap();assert_eq!(element.inner_text(parser),"Hello");

Examples

Finding a tag using the query selector API
let dom = tl::parse(r#"<div><img src="cool-image.png" /></div>"#, tl::ParserOptions::default()).unwrap();let img = dom.query_selector("img[src]").unwrap().next();assert!(img.is_some());
Iterating over the subnodes of an HTML document
let dom = tl::parse(r#"<div><img src="cool-image.png" /></div>"#, tl::ParserOptions::default()).unwrap();let img = dom.nodes().iter().find(|node| {
node.as_tag().map_or(false, |tag| tag.name() == "img")});assert!(img.is_some());
Mutating the `href` attribute of an anchor tag:

In a real world scenario, you would want to handle errors properly instead of unwrapping.

let input = r#"<div><a href="/about">About</a></div>"#;letmut dom = tl::parse(input, tl::ParserOptions::default()).expect("HTML string too long");let anchor = dom.query_selector("a[href]").expect("Failed to parse query selector").next().expect("Failed to find anchor tag");let parser_mut = dom.parser_mut();let anchor = anchor.get_mut(parser_mut).expect("Failed to resolve node").as_tag_mut().expect("Failed to cast Node to HTMLTag");let attributes = anchor.attributes_mut();
attributes.get_mut("href").flatten().expect("Attribute not found or malformed").set("http://localhost/about");assert_eq!(attributes.get("href").flatten(),Some(&"http://localhost/about".into()));

SIMD-accelerated parsing

This crate has utility functions used by the parser which make use of SIMD (e.g. finding a specific byte by looking at the next 16 bytes at once, instead of going through the string one by one). These are disabled by default and must be enabled explicitly by passing the simd feature flag due to the unstable feature portable_simd. This requires a nightly compiler!

If the simd feature is not enabled, it will fall back to stable alternatives that don't explicitly use SIMD intrinsics, but are still decently well optimized, using techniques such as manual loop unrolling to remove boundary checks and other branches by a factor of 16, which also helps LLVM further optimize the code and potentially generate SIMD instructions by itself.

About

Fast, zero-copy HTML Parser written in Rust

Resources

Stars

406 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Repository files navigation

tl

tl is a fast HTML parser written in pure Rust.

This crate (currently) does not strictly follow the full specification of the HTML standard, however this usually is not a problem for most use cases. This crate generally attempts to support most "sane" HTML. Not being limited by a specification allows for more optimization opportunities. If you need a parser that can (very quickly) parse the typical HTML document and you need a simple API to work with the DOM, give this crate a try.

If you need a parser that closely follows the standard, consider using html5ever, lol-html, or html5gum.

Usage

Add tl to your dependencies.

[dependencies]
tl = "0.7.8"# or, with explicit SIMD support# (requires a nightly compiler!)tl = { version = "0.7.8", features = ["simd"] }

The main function is tl::parse(). It accepts an HTML source code string and parses it. It is important to note that tl currently silently ignores tags that are invalid, sort of like browsers do. Sometimes, this means that large chunks of the HTML document do not appear in the resulting tree.

let dom = tl::parse(r#"<p id="text">Hello</p>"#, tl::ParserOptions::default()).unwrap();let parser = dom.parser();let element = dom.get_element_by_id("text").expect("Failed to find element").get(parser).unwrap();assert_eq!(element.inner_text(parser),"Hello");

Examples

Finding a tag using the query selector API
let dom = tl::parse(r#"<div><img src="cool-image.png" /></div>"#, tl::ParserOptions::default()).unwrap();let img = dom.query_selector("img[src]").unwrap().next();assert!(img.is_some());
Iterating over the subnodes of an HTML document
let dom = tl::parse(r#"<div><img src="cool-image.png" /></div>"#, tl::ParserOptions::default()).unwrap();let img = dom.nodes().iter().find(|node| {
node.as_tag().map_or(false, |tag| tag.name() == "img")});assert!(img.is_some());
Mutating the `href` attribute of an anchor tag:

In a real world scenario, you would want to handle errors properly instead of unwrapping.

let input = r#"<div><a href="/about">About</a></div>"#;letmut dom = tl::parse(input, tl::ParserOptions::default()).expect("HTML string too long");let anchor = dom.query_selector("a[href]").expect("Failed to parse query selector").next().expect("Failed to find anchor tag");let parser_mut = dom.parser_mut();let anchor = anchor.get_mut(parser_mut).expect("Failed to resolve node").as_tag_mut().expect("Failed to cast Node to HTMLTag");let attributes = anchor.attributes_mut();
attributes.get_mut("href").flatten().expect("Attribute not found or malformed").set("http://localhost/about");assert_eq!(attributes.get("href").flatten(),Some(&"http://localhost/about".into()));

SIMD-accelerated parsing

This crate has utility functions used by the parser which make use of SIMD (e.g. finding a specific byte by looking at the next 16 bytes at once, instead of going through the string one by one). These are disabled by default and must be enabled explicitly by passing the simd feature flag due to the unstable feature portable_simd. This requires a nightly compiler!

If the simd feature is not enabled, it will fall back to stable alternatives that don't explicitly use SIMD intrinsics, but are still decently well optimized, using techniques such as manual loop unrolling to remove boundary checks and other branches by a factor of 16, which also helps LLVM further optimize the code and potentially generate SIMD instructions by itself.

About

Fast, zero-copy HTML Parser written in Rust

Resources

Stars

406 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

tl

tl is a fast HTML parser written in pure Rust.

This crate (currently) does not strictly follow the full specification of the HTML standard, however this usually is not a problem for most use cases. This crate generally attempts to support most "sane" HTML. Not being limited by a specification allows for more optimization opportunities. If you need a parser that can (very quickly) parse the typical HTML document and you need a simple API to work with the DOM, give this crate a try.

If you need a parser that closely follows the standard, consider using html5ever, lol-html, or html5gum.

Usage

Add tl to your dependencies.

[dependencies]
tl = "0.7.8"# or, with explicit SIMD support# (requires a nightly compiler!)tl = { version = "0.7.8", features = ["simd"] }

The main function is tl::parse(). It accepts an HTML source code string and parses it. It is important to note that tl currently silently ignores tags that are invalid, sort of like browsers do. Sometimes, this means that large chunks of the HTML document do not appear in the resulting tree.

let dom = tl::parse(r#"<p id="text">Hello</p>"#, tl::ParserOptions::default()).unwrap();let parser = dom.parser();let element = dom.get_element_by_id("text").expect("Failed to find element").get(parser).unwrap();assert_eq!(element.inner_text(parser),"Hello");

Examples

Finding a tag using the query selector API
let dom = tl::parse(r#"<div><img src="cool-image.png" /></div>"#, tl::ParserOptions::default()).unwrap();let img = dom.query_selector("img[src]").unwrap().next();assert!(img.is_some());
Iterating over the subnodes of an HTML document
let dom = tl::parse(r#"<div><img src="cool-image.png" /></div>"#, tl::ParserOptions::default()).unwrap();let img = dom.nodes().iter().find(|node| {
node.as_tag().map_or(false, |tag| tag.name() == "img")});assert!(img.is_some());
Mutating the `href` attribute of an anchor tag:

In a real world scenario, you would want to handle errors properly instead of unwrapping.

let input = r#"<div><a href="/about">About</a></div>"#;letmut dom = tl::parse(input, tl::ParserOptions::default()).expect("HTML string too long");let anchor = dom.query_selector("a[href]").expect("Failed to parse query selector").next().expect("Failed to find anchor tag");let parser_mut = dom.parser_mut();let anchor = anchor.get_mut(parser_mut).expect("Failed to resolve node").as_tag_mut().expect("Failed to cast Node to HTMLTag");let attributes = anchor.attributes_mut();
attributes.get_mut("href").flatten().expect("Attribute not found or malformed").set("http://localhost/about");assert_eq!(attributes.get("href").flatten(),Some(&"http://localhost/about".into()));

SIMD-accelerated parsing

This crate has utility functions used by the parser which make use of SIMD (e.g. finding a specific byte by looking at the next 16 bytes at once, instead of going through the string one by one). These are disabled by default and must be enabled explicitly by passing the simd feature flag due to the unstable feature portable_simd. This requires a nightly compiler!

If the simd feature is not enabled, it will fall back to stable alternatives that don't explicitly use SIMD intrinsics, but are still decently well optimized, using techniques such as manual loop unrolling to remove boundary checks and other branches by a factor of 16, which also helps LLVM further optimize the code and potentially generate SIMD instructions by itself.

About

Fast, zero-copy HTML Parser written in Rust

Resources

Stars

406 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

tl

tl is a fast HTML parser written in pure Rust.

This crate (currently) does not strictly follow the full specification of the HTML standard, however this usually is not a problem for most use cases. This crate generally attempts to support most "sane" HTML. Not being limited by a specification allows for more optimization opportunities. If you need a parser that can (very quickly) parse the typical HTML document and you need a simple API to work with the DOM, give this crate a try.

If you need a parser that closely follows the standard, consider using html5ever, lol-html, or html5gum.

Usage

Add tl to your dependencies.

[dependencies]
tl = "0.7.8"# or, with explicit SIMD support# (requires a nightly compiler!)tl = { version = "0.7.8", features = ["simd"] }

The main function is tl::parse(). It accepts an HTML source code string and parses it. It is important to note that tl currently silently ignores tags that are invalid, sort of like browsers do. Sometimes, this means that large chunks of the HTML document do not appear in the resulting tree.

let dom = tl::parse(r#"<p id="text">Hello</p>"#, tl::ParserOptions::default()).unwrap();let parser = dom.parser();let element = dom.get_element_by_id("text").expect("Failed to find element").get(parser).unwrap();assert_eq!(element.inner_text(parser),"Hello");

Examples

Finding a tag using the query selector API
let dom = tl::parse(r#"<div><img src="cool-image.png" /></div>"#, tl::ParserOptions::default()).unwrap();let img = dom.query_selector("img[src]").unwrap().next();assert!(img.is_some());
Iterating over the subnodes of an HTML document
let dom = tl::parse(r#"<div><img src="cool-image.png" /></div>"#, tl::ParserOptions::default()).unwrap();let img = dom.nodes().iter().find(|node| {
node.as_tag().map_or(false, |tag| tag.name() == "img")});assert!(img.is_some());
Mutating the `href` attribute of an anchor tag:

In a real world scenario, you would want to handle errors properly instead of unwrapping.

let input = r#"<div><a href="/about">About</a></div>"#;letmut dom = tl::parse(input, tl::ParserOptions::default()).expect("HTML string too long");let anchor = dom.query_selector("a[href]").expect("Failed to parse query selector").next().expect("Failed to find anchor tag");let parser_mut = dom.parser_mut();let anchor = anchor.get_mut(parser_mut).expect("Failed to resolve node").as_tag_mut().expect("Failed to cast Node to HTMLTag");let attributes = anchor.attributes_mut();
attributes.get_mut("href").flatten().expect("Attribute not found or malformed").set("http://localhost/about");assert_eq!(attributes.get("href").flatten(),Some(&"http://localhost/about".into()));

SIMD-accelerated parsing

This crate has utility functions used by the parser which make use of SIMD (e.g. finding a specific byte by looking at the next 16 bytes at once, instead of going through the string one by one). These are disabled by default and must be enabled explicitly by passing the simd feature flag due to the unstable feature portable_simd. This requires a nightly compiler!

If the simd feature is not enabled, it will fall back to stable alternatives that don't explicitly use SIMD intrinsics, but are still decently well optimized, using techniques such as manual loop unrolling to remove boundary checks and other branches by a factor of 16, which also helps LLVM further optimize the code and potentially generate SIMD instructions by itself.

About

Fast, zero-copy HTML Parser written in Rust

Resources

Stars

406 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Repository files navigation

tl

tl is a fast HTML parser written in pure Rust.

This crate (currently) does not strictly follow the full specification of the HTML standard, however this usually is not a problem for most use cases. This crate generally attempts to support most "sane" HTML. Not being limited by a specification allows for more optimization opportunities. If you need a parser that can (very quickly) parse the typical HTML document and you need a simple API to work with the DOM, give this crate a try.

If you need a parser that closely follows the standard, consider using html5ever, lol-html, or html5gum.

Usage

Add tl to your dependencies.

[dependencies]
tl = "0.7.8"# or, with explicit SIMD support# (requires a nightly compiler!)tl = { version = "0.7.8", features = ["simd"] }

The main function is tl::parse(). It accepts an HTML source code string and parses it. It is important to note that tl currently silently ignores tags that are invalid, sort of like browsers do. Sometimes, this means that large chunks of the HTML document do not appear in the resulting tree.

let dom = tl::parse(r#"<p id="text">Hello</p>"#, tl::ParserOptions::default()).unwrap();let parser = dom.parser();let element = dom.get_element_by_id("text").expect("Failed to find element").get(parser).unwrap();assert_eq!(element.inner_text(parser),"Hello");

Examples

Finding a tag using the query selector API
let dom = tl::parse(r#"<div><img src="cool-image.png" /></div>"#, tl::ParserOptions::default()).unwrap();let img = dom.query_selector("img[src]").unwrap().next();assert!(img.is_some());
Iterating over the subnodes of an HTML document
let dom = tl::parse(r#"<div><img src="cool-image.png" /></div>"#, tl::ParserOptions::default()).unwrap();let img = dom.nodes().iter().find(|node| {
node.as_tag().map_or(false, |tag| tag.name() == "img")});assert!(img.is_some());
Mutating the `href` attribute of an anchor tag:

In a real world scenario, you would want to handle errors properly instead of unwrapping.

let input = r#"<div><a href="/about">About</a></div>"#;letmut dom = tl::parse(input, tl::ParserOptions::default()).expect("HTML string too long");let anchor = dom.query_selector("a[href]").expect("Failed to parse query selector").next().expect("Failed to find anchor tag");let parser_mut = dom.parser_mut();let anchor = anchor.get_mut(parser_mut).expect("Failed to resolve node").as_tag_mut().expect("Failed to cast Node to HTMLTag");let attributes = anchor.attributes_mut();
attributes.get_mut("href").flatten().expect("Attribute not found or malformed").set("http://localhost/about");assert_eq!(attributes.get("href").flatten(),Some(&"http://localhost/about".into()));

SIMD-accelerated parsing

This crate has utility functions used by the parser which make use of SIMD (e.g. finding a specific byte by looking at the next 16 bytes at once, instead of going through the string one by one). These are disabled by default and must be enabled explicitly by passing the simd feature flag due to the unstable feature portable_simd. This requires a nightly compiler!

If the simd feature is not enabled, it will fall back to stable alternatives that don't explicitly use SIMD intrinsics, but are still decently well optimized, using techniques such as manual loop unrolling to remove boundary checks and other branches by a factor of 16, which also helps LLVM further optimize the code and potentially generate SIMD instructions by itself.

About

Fast, zero-copy HTML Parser written in Rust

Resources

Stars

406 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

tl

tl is a fast HTML parser written in pure Rust.

This crate (currently) does not strictly follow the full specification of the HTML standard, however this usually is not a problem for most use cases. This crate generally attempts to support most "sane" HTML. Not being limited by a specification allows for more optimization opportunities. If you need a parser that can (very quickly) parse the typical HTML document and you need a simple API to work with the DOM, give this crate a try.

If you need a parser that closely follows the standard, consider using html5ever, lol-html, or html5gum.

Usage

Add tl to your dependencies.

[dependencies]
tl = "0.7.8"# or, with explicit SIMD support# (requires a nightly compiler!)tl = { version = "0.7.8", features = ["simd"] }

The main function is tl::parse(). It accepts an HTML source code string and parses it. It is important to note that tl currently silently ignores tags that are invalid, sort of like browsers do. Sometimes, this means that large chunks of the HTML document do not appear in the resulting tree.

let dom = tl::parse(r#"<p id="text">Hello</p>"#, tl::ParserOptions::default()).unwrap();let parser = dom.parser();let element = dom.get_element_by_id("text").expect("Failed to find element").get(parser).unwrap();assert_eq!(element.inner_text(parser),"Hello");

Examples

Finding a tag using the query selector API
let dom = tl::parse(r#"<div><img src="cool-image.png" /></div>"#, tl::ParserOptions::default()).unwrap();let img = dom.query_selector("img[src]").unwrap().next();assert!(img.is_some());
Iterating over the subnodes of an HTML document
let dom = tl::parse(r#"<div><img src="cool-image.png" /></div>"#, tl::ParserOptions::default()).unwrap();let img = dom.nodes().iter().find(|node| {
node.as_tag().map_or(false, |tag| tag.name() == "img")});assert!(img.is_some());
Mutating the `href` attribute of an anchor tag:

In a real world scenario, you would want to handle errors properly instead of unwrapping.

let input = r#"<div><a href="/about">About</a></div>"#;letmut dom = tl::parse(input, tl::ParserOptions::default()).expect("HTML string too long");let anchor = dom.query_selector("a[href]").expect("Failed to parse query selector").next().expect("Failed to find anchor tag");let parser_mut = dom.parser_mut();let anchor = anchor.get_mut(parser_mut).expect("Failed to resolve node").as_tag_mut().expect("Failed to cast Node to HTMLTag");let attributes = anchor.attributes_mut();
attributes.get_mut("href").flatten().expect("Attribute not found or malformed").set("http://localhost/about");assert_eq!(attributes.get("href").flatten(),Some(&"http://localhost/about".into()));

SIMD-accelerated parsing

This crate has utility functions used by the parser which make use of SIMD (e.g. finding a specific byte by looking at the next 16 bytes at once, instead of going through the string one by one). These are disabled by default and must be enabled explicitly by passing the simd feature flag due to the unstable feature portable_simd. This requires a nightly compiler!

If the simd feature is not enabled, it will fall back to stable alternatives that don't explicitly use SIMD intrinsics, but are still decently well optimized, using techniques such as manual loop unrolling to remove boundary checks and other branches by a factor of 16, which also helps LLVM further optimize the code and potentially generate SIMD instructions by itself.

About

Fast, zero-copy HTML Parser written in Rust

Resources

Stars

406 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

tl

tl is a fast HTML parser written in pure Rust.

This crate (currently) does not strictly follow the full specification of the HTML standard, however this usually is not a problem for most use cases. This crate generally attempts to support most "sane" HTML. Not being limited by a specification allows for more optimization opportunities. If you need a parser that can (very quickly) parse the typical HTML document and you need a simple API to work with the DOM, give this crate a try.

If you need a parser that closely follows the standard, consider using html5ever, lol-html, or html5gum.

Usage

Add tl to your dependencies.

[dependencies]
tl = "0.7.8"# or, with explicit SIMD support# (requires a nightly compiler!)tl = { version = "0.7.8", features = ["simd"] }

The main function is tl::parse(). It accepts an HTML source code string and parses it. It is important to note that tl currently silently ignores tags that are invalid, sort of like browsers do. Sometimes, this means that large chunks of the HTML document do not appear in the resulting tree.

let dom = tl::parse(r#"<p id="text">Hello</p>"#, tl::ParserOptions::default()).unwrap();let parser = dom.parser();let element = dom.get_element_by_id("text").expect("Failed to find element").get(parser).unwrap();assert_eq!(element.inner_text(parser),"Hello");

Examples

Finding a tag using the query selector API
let dom = tl::parse(r#"<div><img src="cool-image.png" /></div>"#, tl::ParserOptions::default()).unwrap();let img = dom.query_selector("img[src]").unwrap().next();assert!(img.is_some());
Iterating over the subnodes of an HTML document
let dom = tl::parse(r#"<div><img src="cool-image.png" /></div>"#, tl::ParserOptions::default()).unwrap();let img = dom.nodes().iter().find(|node| {
node.as_tag().map_or(false, |tag| tag.name() == "img")});assert!(img.is_some());
Mutating the `href` attribute of an anchor tag:

In a real world scenario, you would want to handle errors properly instead of unwrapping.

let input = r#"<div><a href="/about">About</a></div>"#;letmut dom = tl::parse(input, tl::ParserOptions::default()).expect("HTML string too long");let anchor = dom.query_selector("a[href]").expect("Failed to parse query selector").next().expect("Failed to find anchor tag");let parser_mut = dom.parser_mut();let anchor = anchor.get_mut(parser_mut).expect("Failed to resolve node").as_tag_mut().expect("Failed to cast Node to HTMLTag");let attributes = anchor.attributes_mut();
attributes.get_mut("href").flatten().expect("Attribute not found or malformed").set("http://localhost/about");assert_eq!(attributes.get("href").flatten(),Some(&"http://localhost/about".into()));

SIMD-accelerated parsing

This crate has utility functions used by the parser which make use of SIMD (e.g. finding a specific byte by looking at the next 16 bytes at once, instead of going through the string one by one). These are disabled by default and must be enabled explicitly by passing the simd feature flag due to the unstable feature portable_simd. This requires a nightly compiler!

If the simd feature is not enabled, it will fall back to stable alternatives that don't explicitly use SIMD intrinsics, but are still decently well optimized, using techniques such as manual loop unrolling to remove boundary checks and other branches by a factor of 16, which also helps LLVM further optimize the code and potentially generate SIMD instructions by itself.

About

Fast, zero-copy HTML Parser written in Rust

Resources

Stars

406 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Repository files navigation

tl

tl is a fast HTML parser written in pure Rust.

This crate (currently) does not strictly follow the full specification of the HTML standard, however this usually is not a problem for most use cases. This crate generally attempts to support most "sane" HTML. Not being limited by a specification allows for more optimization opportunities. If you need a parser that can (very quickly) parse the typical HTML document and you need a simple API to work with the DOM, give this crate a try.

If you need a parser that closely follows the standard, consider using html5ever, lol-html, or html5gum.

Usage

Add tl to your dependencies.

[dependencies]
tl = "0.7.8"# or, with explicit SIMD support# (requires a nightly compiler!)tl = { version = "0.7.8", features = ["simd"] }

The main function is tl::parse(). It accepts an HTML source code string and parses it. It is important to note that tl currently silently ignores tags that are invalid, sort of like browsers do. Sometimes, this means that large chunks of the HTML document do not appear in the resulting tree.

let dom = tl::parse(r#"<p id="text">Hello</p>"#, tl::ParserOptions::default()).unwrap();let parser = dom.parser();let element = dom.get_element_by_id("text").expect("Failed to find element").get(parser).unwrap();assert_eq!(element.inner_text(parser),"Hello");

Examples

Finding a tag using the query selector API
let dom = tl::parse(r#"<div><img src="cool-image.png" /></div>"#, tl::ParserOptions::default()).unwrap();let img = dom.query_selector("img[src]").unwrap().next();assert!(img.is_some());
Iterating over the subnodes of an HTML document
let dom = tl::parse(r#"<div><img src="cool-image.png" /></div>"#, tl::ParserOptions::default()).unwrap();let img = dom.nodes().iter().find(|node| {
node.as_tag().map_or(false, |tag| tag.name() == "img")});assert!(img.is_some());
Mutating the `href` attribute of an anchor tag:

In a real world scenario, you would want to handle errors properly instead of unwrapping.

let input = r#"<div><a href="/about">About</a></div>"#;letmut dom = tl::parse(input, tl::ParserOptions::default()).expect("HTML string too long");let anchor = dom.query_selector("a[href]").expect("Failed to parse query selector").next().expect("Failed to find anchor tag");let parser_mut = dom.parser_mut();let anchor = anchor.get_mut(parser_mut).expect("Failed to resolve node").as_tag_mut().expect("Failed to cast Node to HTMLTag");let attributes = anchor.attributes_mut();
attributes.get_mut("href").flatten().expect("Attribute not found or malformed").set("http://localhost/about");assert_eq!(attributes.get("href").flatten(),Some(&"http://localhost/about".into()));

SIMD-accelerated parsing

This crate has utility functions used by the parser which make use of SIMD (e.g. finding a specific byte by looking at the next 16 bytes at once, instead of going through the string one by one). These are disabled by default and must be enabled explicitly by passing the simd feature flag due to the unstable feature portable_simd. This requires a nightly compiler!

If the simd feature is not enabled, it will fall back to stable alternatives that don't explicitly use SIMD intrinsics, but are still decently well optimized, using techniques such as manual loop unrolling to remove boundary checks and other branches by a factor of 16, which also helps LLVM further optimize the code and potentially generate SIMD instructions by itself.

About

Fast, zero-copy HTML Parser written in Rust

Resources

Stars

406 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages