使用 html5ever 遍历 DOM 树时替换元素

问题描述 投票:0回答:1

背景

我需要查找并替换html片段中的一些标签,例如replace

<div class="not-replaced">
    <i18n>Hello World</i18n>
</div>

<div class="not-replaced">
    <span class="i18n" data-location="/index.html:$/i18n">Hello World</span>
</div>

到目前为止我做了什么

我试图通过

html5ever
markup5ever_rcdom
来实现这一点,我想我需要一个递归函数来遍历节点树,但我无法想出一个有效的函数,即创建新节点的函数的签名元素是
RcDom::create_element(&mut self)
,所以我的递归函数需要两个参数:

  1. dom: &mut RcDom
    mut dom: RcDom
    使用
  2. 创建新元素
  3. node: Rc<Node>
    穿越

这很困难,因为我无法传递像

self.traverse(&mut dom, dom.document)
这样的论点。

到目前为止我能找到的唯一有效签名是

fn traverse(&self, dom: &RcDom, node: &Rc<Node>)
,但它没有用,因为
dom
不可变,我无法在其上调用
create_element

这是我现在拥有的代码:

  fn expand_macro(&mut self) {
    let mut html = File::open("index.html").unwrap();
    let mut dom = html5ever::parse_fragment(
      RcDom::default(),
      html5ever::ParseOpts::default(),
      QualName::new(None, ns!(html), local_name!("div")),
      vec![],
    )
    .from_utf8()
    .read_from(&mut html)
    .unwrap();

    self.traverse(&mut dom, dom.document);
  }

  fn traverse(&mut self, dom: &mut RcDom, node: Rc<Node>) {
  }

我需要什么

如何重写代码,这样我就可以访问

&mut RcDom
Rc<Node>
来遍历。

或其他一些建议来实现我在背景中描述的相同目标。

谢谢,非常感谢您的帮助!

rust html5ever
1个回答
0
投票

这可以看作是一个“迭代时修改”的问题,我的解决方案是:

  1. 收集第一次迭代中需要处理的所有元素,
  2. 然后在第二次迭代中应用这些更改

代码片段如下所示:

pub struct HtmlMacro {
  pub location: String,
  pub parent_node: Rc<Node>,
  pub index: usize,
  pub text: String,
}

fn expand_macro_html(source: String, source_path: &Path) -> String {
  // parse dom
  let mut dom = html5ever::parse_fragment(/* options */)
                  .from_utf8()
                  .one(source.as_bytes());

  // the first iteration only needs a readonly reference to dom
  // collect_html_macros(dom: &RcDom, file_path: &Path) -> Vec<HtmlMacro>
  let macros = collect_html_macros(&dom, source_path);

  // the second iteration has a mutable reference to dom
  // expand macros
  for m in macros {
    let mut children = m.parent_node.children.borrow_mut();
    let expanded_macro = dom.create_element(/* new element */);
    children[m.index] = expanded_macro;
  }

  // serialize
  // return serialized document
}
© www.soinside.com 2019 - 2024. All rights reserved.