#![crate_name = "dom_content_extraction"]
use ego_tree::NodeId;
pub mod cetd;
pub mod tree;
pub mod unicode;
pub mod utils;
#[cfg(feature = "markdown")]
pub mod markdown;
pub use cetd::{DensityNode, DensityTree};
pub use utils::{get_node_links, get_node_text};
#[cfg(feature = "markdown")]
pub use markdown::extract_content_as_markdown;
pub use scraper;
#[derive(Debug, thiserror::Error)]
pub enum DomExtractionError {
#[error("Failed to access tree node: {0:?}")]
NodeAccessError(NodeId),
}
pub fn get_content(document: &scraper::Html) -> Result<String, DomExtractionError> {
let mut dtree = DensityTree::from_document(document)?;
dtree.calculate_density_sum()?;
dtree.extract_content(document)
}
pub fn get_article(document: &scraper::Html) -> Result<String, DomExtractionError> {
let mut dtree = DensityTree::from_document(document)?;
dtree.calculate_density_sum()?;
dtree.extract_article(document)
}
#[cfg(test)]
#[allow(clippy::unwrap_used)]
mod tests {
use super::*;
const TEST_1_HTML: &str = include_str!("../html/test_1.html");
#[test]
fn get_content_returns_article_text() {
let document = scraper::Html::parse_document(TEST_1_HTML);
let content = get_content(&document).unwrap();
assert!(
content.contains("Here is article"),
"get_content should return the article body:\n{content}"
);
assert!(content.contains("Even more huge"));
assert!(
!content.contains("Menu"),
"get_content should exclude navigation:\n{content}"
);
}
#[test]
fn get_article_excludes_ticker() {
let html = r#"<html><body>
<div class="ticker">
<a href="/1">Breaking: Aave Labs secures UK license</a>
<a href="/2">SpaceX perps plunge 45% on Hyperliquid</a>
<a href="/3">Paxos secures SEC registration</a>
</div>
<article>
<h1>Treasury Secretary reiterates no CBDC commitment</h1>
<p>U.S. Treasury Secretary Scott Bessent reiterated that the current
administration will not allow a central bank digital currency
(CBDC). During a White House press briefing, Bessent said CBDCs are
clearly off the table and reaffirmed the administration's focus on
making the U.S. a hub for digital assets. Bessent also mentioned
that the GENIUS stablecoin legislation passed with bipartisan
support, and the Clarity Act is gaining similar legislative
momentum.</p>
</article>
</body></html>"#;
let document = scraper::Html::parse_document(html);
let article = get_article(&document).unwrap();
assert!(article.contains("Scott Bessent"));
assert!(article.contains("CBDC"));
assert!(
!article.contains("Aave Labs"),
"ticker leaked through get_article:\n{article}"
);
assert!(!article.contains("SpaceX"));
assert!(!article.contains("Hyperliquid"));
}
#[test]
fn get_article_on_contentless_document_returns_empty() {
let html = r#"<html><body><script>var x = 1;</script></body></html>"#;
let document = scraper::Html::parse_document(html);
let article = get_article(&document).unwrap();
assert!(
article.trim().is_empty(),
"expected empty output for contentless HTML, got:\n{article}"
);
}
}