diff --git a/crates/idx-core/src/api/ipot/parse.rs b/crates/idx-core/src/api/ipot/parse.rs index 00b5cee..7a6ac58 100644 --- a/crates/idx-core/src/api/ipot/parse.rs +++ b/crates/idx-core/src/api/ipot/parse.rs @@ -163,10 +163,21 @@ fn cell(td: ElementRef) -> Option<(String, Option)> { Some((clean(&text), class)) } -/// The `MM/DD/YYYY` value of the one input with this id. +/// Whether `element` sits in plain divs only, as IPOT's table and date +/// inputs do; inside anything else (details, dialog, noscript, object, +/// select, ...) it may not show. +fn in_divs(element: ElementRef) -> bool { + element + .ancestors() + .filter_map(ElementRef::wrap) + .all(|ancestor| matches!(ancestor.value().name(), "div" | "html")) +} + +/// The `MM/DD/YYYY` value of the one input with this id, in plain divs. fn input_date(page: &Html, id: &str) -> Option { - let value = only(page.root_element(), &format!("input#{id}"))?.attr("value")?; - NaiveDate::parse_from_str(value.trim(), "%m/%d/%Y").ok() + let input = + only(page.root_element(), &format!("input#{id}")).filter(|input| in_divs(*input))?; + NaiveDate::parse_from_str(input.attr("value")?.trim(), "%m/%d/%Y").ok() } /// Whether anything in the page is hidden by markup alone (`hidden`, an @@ -200,6 +211,9 @@ pub fn parse_broker_summary(html: &str) -> Result { } let table = only(page.root_element(), "table") .ok_or_else(|| parse_error("no single table in the page"))?; + if !in_divs(table) { + return Err(parse_error("the table is not in plain page markup")); + } let body = only(table, "tbody").ok_or_else(|| parse_error("no single table body"))?; let mut raw = BrokerSummaryRaw { from: input_date(&page, "startDateBrokerSummary"), @@ -490,6 +504,22 @@ mod tests { 1, ), ), + ( + "the table in a select", + DAY.replacen("", + "", + 1, + ), + ), + ( + "the table in closed details", + DAY.replacen("", + "", + 1, + ), + ), ("no table", "".to_string()), // Text a browser would not show, or not as one figure or code. ( @@ -589,16 +619,6 @@ mod tests { 1, ), ), - // The HTML standard keeps a table inside a select since its 2025 - // select parsing change; html5ever and current browsers agree. - ( - "the table in a select", - DAY.replacen("", - "", - 1, - ), - ), ( "a script after the table", DAY.replacen("", "", 1), @@ -626,5 +646,11 @@ mod tests { None, "an id twice is no echoed date" ); + let closed = DAY.replacen("