use svgparser::{
TextUnescape,
XmlSpace,
};
use {
Attribute,
AttributeId,
AttributeValue,
Document,
Name,
Node,
NodeType,
};
trait StrTrim {
fn remove_first(&mut self);
fn remove_last(&mut self);
}
impl StrTrim for String {
fn remove_first(&mut self) {
self.drain(0..1);
}
fn remove_last(&mut self) {
self.pop();
}
}
pub fn prepare_text(dom: &mut Document) {
_prepare_text(&dom.root(), XmlSpace::Default);
for mut node in dom.descendants().filter(|n| n.node_type() == NodeType::Element) {
node.attributes_mut().retain(|attr| attr.visible);
}
dom.drain(|n| n.node_type() == NodeType::Text && n.text().is_empty());
}
fn _prepare_text(parent: &Node, parent_xmlspace: XmlSpace) {
let mut xmlspace = parent_xmlspace;
for mut node in parent.children().filter(|n| n.node_type() == NodeType::Element) {
xmlspace = get_xmlspace(&mut node, xmlspace);
if let Some(child) = node.first_child() {
if child.node_type() == NodeType::Text {
prepare_text_children(&node, xmlspace);
continue;
}
}
_prepare_text(&node, xmlspace);
}
}
fn get_xmlspace(node: &mut Node, default: XmlSpace) -> XmlSpace {
{
let attrs = node.attributes();
let v = attrs.get_value(AttributeId::XmlSpace);
if let Some(&AttributeValue::String(ref s)) = v {
if s == "preserve" {
return XmlSpace::Preserve;
} else {
return XmlSpace::Default;
}
}
}
set_xmlspace(node, default);
default
}
fn set_xmlspace(node: &mut Node, xmlspace: XmlSpace) {
let xmlspace_str = match xmlspace {
XmlSpace::Default => "default",
XmlSpace::Preserve => "preserve",
};
let attr = Attribute {
name: Name::Id(AttributeId::XmlSpace),
value: AttributeValue::String(xmlspace_str.to_owned()),
visible: false,
};
node.set_attribute(attr);
}
fn prepare_text_children(parent: &Node, xmlspace: XmlSpace) {
for mut child in parent.descendants() {
if child.node_type() == NodeType::Text {
let child_xmlspace = get_xmlspace(&mut child.parent().unwrap(), xmlspace);
let new_text = {
let text = child.text();
TextUnescape::unescape(text.as_ref(), child_xmlspace)
};
child.set_text(&new_text);
}
}
let mut nodes: Vec<Node> = parent.descendants()
.filter(|n| n.node_type() == NodeType::Text)
.collect();
if nodes.len() == 1 {
let node = &mut nodes[0];
if xmlspace == XmlSpace::Default {
let mut text = node.text_mut();
match text.len() {
0 => {} 1 => {
if text.as_bytes()[0] == b' ' {
text.clear();
}
}
_ => {
let c1 = text.as_bytes()[0];
let c2 = text.as_bytes()[text.len() - 1];
if c1 == b' ' {
text.remove_first();
}
if c2 == b' ' {
text.remove_last();
}
}
}
} else {
}
} else if nodes.len() > 1 {
let mut i = 0;
let len = nodes.len() - 1;
let mut last_non_empty: Option<Node> = None;
while i < len {
let mut node1 = nodes[i].clone();
let mut node2 = nodes[i + 1].clone();
if node1.text().is_empty() {
if let Some(ref n) = last_non_empty {
node1 = n.clone();
}
}
let xmlspace1 = get_xmlspace(&mut node1.parent().unwrap(), xmlspace);
let xmlspace2 = get_xmlspace(&mut node2.parent().unwrap(), xmlspace);
let (c1, c2, c3, c4) = {
let text1 = node1.text();
let text2 = node2.text();
let bytes1 = text1.as_bytes();
let bytes2 = text2.as_bytes();
let c1 = bytes1.first().cloned();
let c2 = bytes1.last().cloned();
let c3 = bytes2.first().cloned();
let c4 = bytes2.last().cloned();
(c1, c2, c3, c4)
};
if xmlspace1 == XmlSpace::Default
&& xmlspace2 == XmlSpace::Default
{
if c2 == Some(b' ') && c2 == c3 {
node2.text_mut().remove_first();
}
}
let is_first = i == 0;
let is_last = i == len - 1;
if is_first
&& c1 == Some(b' ')
&& xmlspace1 == XmlSpace::Default
{
node1.text_mut().remove_first();
} else if is_last
&& c4 == Some(b' ')
&& !node2.text().is_empty()
&& xmlspace2 == XmlSpace::Default
{
node2.text_mut().remove_last();
}
if is_last
&& c2 == Some(b' ')
&& !node1.text().is_empty()
&& node2.text().is_empty()
{
node1.text_mut().remove_last();
}
if !node1.text().trim().is_empty() {
last_non_empty = Some(node1.clone());
}
i += 1;
}
}
}