///|
/// Parse a full HTML document from a string.
///
/// The returned root is a document node with the usual `html`, `head`, and
/// `body` scaffolding. Set `sanitize=true` to apply the default document
/// sanitizer after parsing, `collect_errors=true` to keep parse diagnostics, and
/// `strict=true` to raise `@core.HtmlError::StrictMode` on the first parse error.
pub fn parse(
html : StringView,
sanitize? : Bool = false,
collect_errors? : Bool = false,
strict? : Bool = false,
scripting_enabled? : Bool = true,
xml_coercion? : Bool = false,
track_node_locations? : Bool = false,
) -> ParsedHtml raise @core.HtmlError {
let root = @dom.document()
let parser = Parser::new(
html,
root,
scripting_enabled~,
xml_coercion~,
track_node_locations~,
)
parser.deferred_initial_doctype_error = parser.report_initial_doctype_error()
parser.parse_all()
parser.flush_deferred_initial_doctype_error()
parser.report_eof_tree_errors()
scaffold_document(root)
parser.apply_pending_document_html_attrs()
append_post_body_html_children(root, parser.post_body_html_children)
normalize_tables(root)
populate_selectedcontent(root)
let errors = if collect_errors || strict { parser.errors } else { [] }
if strict && !parser.errors.is_empty() {
raise StrictMode(parser.errors[0])
}
if sanitize {
ignore(@san.sanitize_dom(root))
}
{ root, errors, encoding: None }
}
///|
/// Parse an HTML fragment from a string.
///
/// `context` controls the fragment context element used by the tree builder.
/// Without a context, the fragment is parsed into a generic fragment root.
/// `sanitize`, `collect_errors`, `strict`, `scripting_enabled`, `xml_coercion`,
/// and `track_node_locations` have the same meaning as in `parse`.
pub fn parse_fragment(
html : StringView,
context? : FragmentContext,
sanitize? : Bool = false,
collect_errors? : Bool = false,
strict? : Bool = false,
scripting_enabled? : Bool = true,
xml_coercion? : Bool = false,
track_node_locations? : Bool = false,
) -> ParsedHtml raise @core.HtmlError {
let root = @dom.fragment()
let parser = Parser::new(
html,
root,
scripting_enabled~,
xml_coercion~,
track_node_locations~,
)
match context {
Some(fragment_context) =>
if !parser.parse_fragment_context(fragment_context) {
parser.parse_all()
}
None => parser.parse_all()
}
parser.report_eof_tree_errors()
normalize_tables(root)
populate_selectedcontent(root)
let errors = if collect_errors || strict { parser.errors } else { [] }
if strict && !parser.errors.is_empty() {
raise StrictMode(parser.errors[0])
}
if sanitize {
ignore(@san.sanitize_dom(root))
}
{ root, errors, encoding: None }
}
///|
/// Decode and parse an HTML byte stream.
///
/// When `encoding` is absent, BOMs and `` declarations are
/// sniffed before falling back to Windows-1252. The detected or requested
/// encoding is stored in `ParsedHtml.encoding`.
pub fn parse_bytes(
input : BytesView,
encoding? : String,
sanitize? : Bool = false,
collect_errors? : Bool = false,
strict? : Bool = false,
scripting_enabled? : Bool = true,
xml_coercion? : Bool = false,
track_node_locations? : Bool = false,
) -> ParsedHtml raise @core.HtmlError {
let (decoded, detected_encoding) = @enc.decode_html_bytes(input, encoding)
let parsed = parse(
decoded,
sanitize~,
collect_errors~,
strict~,
scripting_enabled~,
xml_coercion~,
track_node_locations~,
)
{
root: parsed.root,
errors: parsed.errors,
encoding: Some(detected_encoding),
}
}
///|
/// Serialize the parsed root node back to HTML.
///
/// This forwards to `to_html` on `self.root`.
pub fn ParsedHtml::to_html(
self : ParsedHtml,
pretty? : Bool = true,
indent_size? : Int = 2,
context? : @ser.HtmlContext = Html,
quote? : Char = '"',
) -> String raise @core.HtmlError {
@ser.to_html(self.root, pretty~, indent_size~, context~, quote~)
}
///|
/// Extract text from the parsed root node.
///
/// This forwards to `to_text` on `self.root`.
pub fn ParsedHtml::to_text(
self : ParsedHtml,
separator? : String = " ",
strip? : Bool = true,
separator_blocks_only? : Bool = false,
) -> String {
@ser.to_text(self.root, separator~, strip~, separator_blocks_only~)
}
///|
/// Render the parsed document or fragment root as Markdown.
///
/// This is equivalent to calling `to_markdown` on `self.root`.
pub fn ParsedHtml::to_markdown(
self : ParsedHtml,
html_passthrough? : Bool = false,
) -> String raise @core.HtmlError {
@md.to_markdown(self.root, html_passthrough~)
}
///|
/// Return all descendants of the parsed root that match a CSS selector.
pub fn ParsedHtml::query(
self : ParsedHtml,
selector : StringView,
) -> Array[@dom.Node] {
@sel.query(self.root, selector)
}
///|
/// Return the first descendant of the parsed root that matches a CSS selector.
pub fn ParsedHtml::query_one(
self : ParsedHtml,
selector : StringView,
) -> @dom.Node? {
@sel.query_one(self.root, selector)
}