use crate::namespaces::W;
use crate::util::group_adjacent;
use crate::xmllinq::{Dom, NodeId, XName, XNamespace};
fn xml_space() -> XName {
XNamespace::xml().name("space")
}
fn build_run(dom: &mut Dom, rpr_elems: &[NodeId], inner: NodeId) -> NodeId {
let run = dom.new_element(W::r());
for &rpr in rpr_elems {
dom.add(run, rpr); }
dom.add(run, inner);
run
}
fn copy_attrs(dom: &mut Dom, src: NodeId, dst: NodeId) {
for (name, value) in dom.attributes(src) {
dom.set_attribute_value(dst, &name, Some(&value));
}
}
pub fn single_character_run_transform(dom: &mut Dom, node: NodeId) -> Vec<NodeId> {
if !dom.is_element(node) {
return vec![node];
}
let name = dom.name(node).unwrap();
if name == W::r() {
let rpr_elems = dom.elements(node, Some(&W::r_pr()));
let non_rpr: Vec<NodeId> = dom
.elements(node, None)
.into_iter()
.filter(|&e| dom.name(e).unwrap() != W::r_pr())
.collect();
let mut out: Vec<NodeId> = Vec::new();
let groups = group_adjacent(non_rpr, |&e| dom.name(e).unwrap() == W::t());
for (is_t, group) in groups {
if is_t {
let mut s = String::new();
for &t in &group {
s.push_str(&dom.value(t));
}
for c in s.chars() {
let t = dom.new_element(W::t());
if c == ' ' {
dom.set_attribute_value(t, &xml_space(), Some("preserve"));
}
dom.add_text(t, &c.to_string());
let run = build_run(dom, &rpr_elems, t);
out.push(run);
}
} else {
for sr in group {
let sr_name = dom.name(sr).unwrap();
let ne = dom.new_element(sr_name);
copy_attrs(dom, sr, ne);
for child in dom.nodes(sr) {
let transformed = single_character_run_transform(dom, child);
for tn in transformed {
dom.add(ne, tn);
}
}
let run = build_run(dom, &rpr_elems, ne);
out.push(run);
}
}
}
return out;
}
let ne = dom.new_element(name);
copy_attrs(dom, node, ne);
for child in dom.nodes(node) {
let transformed = single_character_run_transform(dom, child);
for tn in transformed {
dom.add(ne, tn);
}
}
vec![ne]
}
pub fn transform_element_to_single_character_runs(dom: &mut Dom, element: NodeId) -> NodeId {
let v = single_character_run_transform(dom, element);
debug_assert_eq!(v.len(), 1, "root transform must yield exactly one node");
v[0]
}
fn is_rsid_attr(name: &XName) -> bool {
if name.namespace_name() != W::URI {
return false;
}
matches!(
name.local_name(),
"rsid" | "rsidDel" | "rsidP" | "rsidR" | "rsidRDefault" | "rsidRPr" | "rsidSect" | "rsidTr"
)
}
pub fn remove_rsid_transform(dom: &mut Dom, node: NodeId) -> Option<NodeId> {
if !dom.is_element(node) {
return Some(node);
}
let name = dom.name(node).unwrap();
if name == W::name("rsid") {
return None;
}
let rsid_attrs: Vec<_> = dom
.attributes(node)
.into_iter()
.filter(|(an, _)| is_rsid_attr(an))
.map(|(an, _)| an)
.collect();
for an in &rsid_attrs {
dom.set_attribute_value(node, an, None);
}
let kids: Vec<NodeId> = (0..dom.child_count(node))
.map(|i| dom.child_at(node, i))
.collect();
for k in kids {
if remove_rsid_transform(dom, k).is_none() {
dom.remove(k);
}
}
Some(node)
}