From 4c8fc2523cf3bf6cd6199bb36a70c1d12cd64883 Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Sat, 20 Dec 2025 17:38:34 -0800 Subject: [PATCH] work --- rust/pspp/src/spv/read/html.rs | 86 +++++++++++++++++++++++++--------- 1 file changed, 65 insertions(+), 21 deletions(-) diff --git a/rust/pspp/src/spv/read/html.rs b/rust/pspp/src/spv/read/html.rs index c4cb7ba7c4..19dc709766 100644 --- a/rust/pspp/src/spv/read/html.rs +++ b/rust/pspp/src/spv/read/html.rs @@ -269,29 +269,73 @@ impl Markup { writer.write_event(Event::Text(BytesText::new(&format!("&[{name}]"))))? } Markup::Style { style, child } => { - match style { - Style::Bold => writer.create_element("b"), - Style::Italic => writer.create_element("i"), - Style::Underline => writer.create_element("u"), - Style::Strike => writer.create_element("strike"), - Style::Emphasis => writer.create_element("em"), - Style::Strong => writer.create_element("strong"), - Style::Face(face) => writer - .create_element("font") - .with_attribute(("face", face.as_str())), - Style::Color(color) => writer - .create_element("font") - .with_attribute(("color", color.display_css().to_string().as_str())), - Style::Size(points) => writer - .create_element("font") - .with_attribute(("size", format!("{}pt", *points / 0.75).as_str())), + let mut elements = Vec::new(); + let mut attributes = Vec::new(); + fn add_style( + style: &Style, + elements: &mut Vec<&'static str>, + attributes: &mut Vec<(&'static str, String)>, + ) { + match style { + Style::Bold => elements.push("b"), + Style::Italic => elements.push("i"), + Style::Underline => elements.push("u"), + Style::Strike => elements.push("strike"), + Style::Emphasis => elements.push("em"), + Style::Strong => elements.push("strong"), + Style::Face(face) => attributes.push(("face", face.clone())), + Style::Color(color) => { + attributes.push(("color", color.display_css().to_string())) + } + Style::Size(points) => { + attributes.push(("size", format!("{}pt", *points / 0.75))) + } + } } - .write_inner_content(|w| child.write_html(w))?; + + add_style(style, &mut elements, &mut attributes); + let mut next = &**child; + while let Markup::Style { style, child } = next { + add_style(style, &mut elements, &mut attributes); + next = &**child; + } + + elements.sort(); + attributes.sort(); + next.write_styles(writer, &elements, &attributes)?; } } Ok(()) } + fn write_styles( + &self, + writer: &mut XmlWriter, + elements: &[&str], + attributes: &[(&str, String)], + ) -> std::io::Result<()> + where + X: Write, + { + if !attributes.is_empty() { + writer + .create_element("font") + .with_attributes( + attributes + .into_iter() + .map(|(name, value)| (*name, Cow::from(value))), + ) + .write_inner_content(|w| self.write_styles(w, elements, &[]))?; + } else if let Some((element, rest)) = elements.split_first() { + writer + .create_element(*element) + .write_inner_content(|w| self.write_styles(w, rest, attributes))?; + } else { + self.write_html(writer)?; + } + Ok(()) + } + /// Returns this markup converted into XHTML. The returned string contains /// a single `...` element. /// @@ -901,7 +945,7 @@ mod tests { let content = quick_xml::de::from_str::(text).unwrap(); assert_eq!( Document::from_html(&content).to_html(), - r##"

plain bold italic strikeout

"## + r##"

plain bold italic strikeout

"## ); } @@ -922,7 +966,7 @@ mod tests { let content = quick_xml::de::from_str::(text).unwrap(); assert_eq!( Document::from_html(&content).to_html(), - r##"

left

center large

right

"## + r##"

left

center large

right

"## ); } @@ -1007,7 +1051,7 @@ mod tests { let document = Document::from_html(&content); assert_eq!( document.to_html(), - r##"

&[PageTitle]

"## + r##"

&[PageTitle]

"## ); assert_eq!( document.0[0] @@ -1042,7 +1086,7 @@ mod tests { let html = Document::from_html(&content); assert_eq!( html.to_html(), - r##"

Page &[Page]

"## + r##"

Page &[Page]

"## ); } -- 2.30.2