diff --git a/src/xhtml.rs b/src/xhtml.rs
index 43ea9e6..7661093 100644
--- a/src/xhtml.rs
+++ b/src/xhtml.rs
@@ -18,7 +18,7 @@ type Lang = String;
#[derive(Debug, Clone)]
pub struct XhtmlIm {
/// Map of language to body element.
- bodies: HashMap,
+ bodies: HashMap,
}
impl XhtmlIm {
@@ -27,22 +27,41 @@ impl XhtmlIm {
let mut html = Vec::new();
// TODO: use the best language instead.
for (lang, body) in self.bodies {
- if let Tag::Body { style: _, xml_lang, children } = body {
- if lang.is_empty() {
- assert!(xml_lang.is_none());
- } else {
- assert_eq!(Some(lang), xml_lang);
- }
- for tag in children {
- html.push(tag.to_html());
- }
- break;
+ if lang.is_empty() {
+ assert!(body.xml_lang.is_none());
} else {
- unreachable!();
+ assert_eq!(Some(lang), body.xml_lang);
}
+ for tag in body.children {
+ html.push(tag.to_html());
+ }
+ break;
}
html.concat()
}
+
+ /// Removes all unknown elements.
+ pub fn flatten(self) -> XhtmlIm {
+ let mut bodies = HashMap::new();
+ for (lang, body) in self.bodies {
+ let children = body.children.into_iter().fold(vec![], |mut acc, child| {
+ match child {
+ Child::Tag(Tag::Unknown(children)) => acc.extend(children),
+ any => acc.push(any),
+ }
+ acc
+ });
+ let body = Body {
+ style: body.style,
+ xml_lang: body.xml_lang,
+ children,
+ };
+ bodies.insert(lang, body);
+ }
+ XhtmlIm {
+ bodies,
+ }
+ }
}
impl MessagePayload for XhtmlIm {}
@@ -62,7 +81,7 @@ impl TryFrom for XhtmlIm {
Some(lang) => lang,
None => "",
}.to_string();
- let body = Tag::try_from(child)?;
+ let body = Body::try_from(child)?;
match bodies.insert(lang, body) {
None => (),
Some(_) => return Err(Error::ParseError("Two identical language bodies found in XHTML-IM."))
@@ -81,16 +100,12 @@ impl From for Element {
Element::builder("html")
.ns(ns::XHTML_IM)
.append(wrapper.bodies.into_iter().map(|(ref lang, ref body)| {
- if let Tag::Body { style, xml_lang, children } = body {
- assert_eq!(Some(lang), xml_lang.as_ref());
- Element::builder("body")
- .ns(ns::XHTML_IM)
- .attr("style", get_style_string(style.clone()))
- .attr("xml:lang", xml_lang.clone())
- .append(children_to_nodes(children.clone()))
- } else {
- unreachable!();
- }
+ assert_eq!(Some(lang), body.xml_lang.as_ref());
+ Element::builder("body")
+ .ns(ns::XHTML_IM)
+ .attr("style", get_style_string(body.style.clone()))
+ .attr("xml:lang", body.xml_lang.clone())
+ .append(children_to_nodes(body.children.clone()))
}).collect::>())
.build()
}
@@ -130,11 +145,45 @@ fn get_style_string(style: Css) -> Option {
Some(result.join("; "))
}
+#[derive(Debug, Clone)]
+struct Body {
+ style: Css,
+ xml_lang: Option,
+ children: Vec,
+}
+
+impl TryFrom for Body {
+ type Error = Error;
+
+ fn try_from(elem: Element) -> Result {
+ let mut children = vec![];
+ for child in elem.nodes() {
+ match child {
+ Node::Element(child) => children.push(Child::Tag(Tag::try_from(child.clone())?)),
+ Node::Text(text) => children.push(Child::Text(text.clone())),
+ Node::Comment(_) => unimplemented!() // XXX: remove!
+ }
+ }
+
+ Ok(Body { style: parse_css(elem.attr("style")), xml_lang: elem.attr("xml:lang").map(|xml_lang| xml_lang.to_string()), children })
+ }
+}
+
+impl From for Element {
+ fn from(body: Body) -> Element {
+ Element::builder("body")
+ .ns(ns::XHTML)
+ .attr("style", get_style_string(body.style))
+ .attr("xml:lang", body.xml_lang)
+ .append(children_to_nodes(body.children))
+ .build()
+ }
+}
+
#[derive(Debug, Clone)]
enum Tag {
A { href: Option, style: Css, type_: Option, children: Vec },
Blockquote { style: Css, children: Vec },
- Body { style: Css, xml_lang: Option, children: Vec },
Br,
Cite { style: Css, children: Vec },
Em { children: Vec },
@@ -161,10 +210,6 @@ impl Tag {
let style = write_attr(get_style_string(style), "style");
format!("{}
", style, children_to_html(children))
},
- Tag::Body { style, xml_lang: _, children } => {
- let style = write_attr(get_style_string(style), "style");
- format!("{}", style, children_to_html(children))
- },
Tag::Br => String::from("
"),
Tag::Cite { style, children } => {
let style = write_attr(get_style_string(style), "style");
@@ -218,7 +263,6 @@ impl TryFrom for Tag {
Ok(match elem.name() {
"a" => Tag::A { href: elem.attr("href").map(|href| href.to_string()), style: parse_css(elem.attr("style")), type_: elem.attr("type").map(|type_| type_.to_string()), children },
"blockquote" => Tag::Blockquote { style: parse_css(elem.attr("style")), children },
- "body" => Tag::Body { style: parse_css(elem.attr("style")), xml_lang: elem.attr("xml:lang").map(|xml_lang| xml_lang.to_string()), children },
"br" => Tag::Br,
"cite" => Tag::Cite { style: parse_css(elem.attr("style")), children },
"em" => Tag::Em { children },
@@ -254,16 +298,6 @@ impl From for Element {
Some(style) => vec![("style", style)],
None => vec![],
}, children),
- Tag::Body { style, xml_lang, children } => ("body", {
- let mut attrs = vec![];
- if let Some(style) = get_style_string(style) {
- attrs.push(("style", style));
- }
- if let Some(xml_lang) = xml_lang {
- attrs.push(("xml:lang", xml_lang));
- }
- attrs
- }, children),
Tag::Br => ("br", vec![], vec![]),
Tag::Cite { style, children } => ("cite", match get_style_string(style) {
Some(style) => vec![("style", style)],
@@ -405,26 +439,17 @@ mod tests {
let elem: Element = ""
.parse()
.unwrap();
- let body = Tag::try_from(elem).unwrap();
- match body {
- Tag::Body { style: _, xml_lang: _, children } => assert_eq!(children.len(), 0),
- _ => panic!(),
- }
+ let body = Body::try_from(elem).unwrap();
+ assert_eq!(body.children.len(), 0);
let elem: Element = "Hello world!
"
.parse()
.unwrap();
- let body = Tag::try_from(elem).unwrap();
- let mut children = match body {
- Tag::Body { style, xml_lang, children } => {
- assert_eq!(style.len(), 0);
- assert_eq!(xml_lang, None);
- assert_eq!(children.len(), 1);
- children
- },
- _ => panic!(),
- };
- let p = match children.pop() {
+ let mut body = Body::try_from(elem).unwrap();
+ assert_eq!(body.style.len(), 0);
+ assert_eq!(body.xml_lang, None);
+ assert_eq!(body.children.len(), 1);
+ let p = match body.children.pop() {
Some(Child::Tag(tag)) => tag,
_ => panic!(),
};