选择某些元素,同时避免其他嵌套元素

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

我想用正则表达式查找并替换一些*innerHTML *。我想在一个文档中执行此操作,作用于除锚元素之外的所有内容。

我想我可以使用 queryselectorAll 来做到这一点,通过将其设置为选择除锚元素之外的所有元素。问题在于锚元素嵌套在元素内,如下面的代码所示。因此,即使我排除锚元素,我仍然在正则表达式中遍历它们,因为它们嵌套在由查询选择器捕获的其他元素中(下面,嵌套在 para 元素中)。

我的下一步是尝试排除作为锚元素父级的所有元素。但这会导致 HTML 从我的正则表达式搜索中丢失。例如,在文本下面的 para 元素中“hello I am some text”是“p”元素的 *child *。因此,通过排除“p”元素,该文本超出了我的正则表达式的范围。我需要将该文本包含在我的正则表达式中。

<p class="1 2">
  <span class="3">
   some writing here
    <strong class="4">some more here</strong>
  </span>
  <strong class="5">
    <span class="6">
      <span class="7"></span>
      <a class="8" href="#abc" title="TITLE" id="9">some text</a>
      <span class="10">some text</span>
      <span class="11"></span>
    </span>
    <span class="12"></span>
  </strong>
  hello I am some text
</p>

还有两个进一步的复杂性。首先,我需要遍历的文档非常长,大约有 250,000 个 HTML 单词,全部采用复杂的嵌套格式,深度可能为 10 - 15 层。其次,它不是我正在运行的单个正则表达式。我有一个包含 300 个正则表达式的数组。我需要遍历文档来查找这 300 个正则表达式中的每一个。关键是它非常耗费资源和时间。目前运行我的代码大约需要一个小时。但该代码是错误的,因为它作用于锚元素。

我想简单地沿线删除锚元素:

anchors.forEach((anchor) => anchor.parentNode.removeChild(anchor));

但是我留下了一个缺少锚元素的文档,我在文档中需要它们,我只是不想用正则表达式遍历它们。我想过记录已删除锚点元素的位置,然后在正则表达式之后重新插入它们,但这一切都变得非常复杂,因为我将插入新的跨度,从而使跟踪相关锚点应重新插入的位置变得复杂。这个方法变得太复杂了。

我将不胜感激有关如何继续的建议。有没有办法避免遍历**嵌套**锚元素?

编辑1。 如果我的问题不清楚,我深表歉意,并感谢您提供真正有用的答复。我已经学到了很多东西。这是一些进一步的解释。

这是 html 的另一个示例

<p class="A B">
  <span class="H LegLHS F" id="123">
    <span class="D">
      <span class="C">(b)</span>
    </span>
  </span>
  <span class="H G LegP3Text">
    <a class="LegCitation" title="Go to item" rel="cite" href="/uk/directive/2020/0044">
      <span class="D">
        <span class="C">Directive 2020/44/UK</span>
      </span>
    </a>
    <span class="D">
      <span class="C"> UK law which is a directive </span>
    </span>
    <a class="Citation" title="Go to item" rel="cite" href="/uk/directive/2020/0044">
      <span class="D">
        <span class="C"> Directive 2020/44/UK </span>
      </span>
    </a>
    <span class="D">
      <span class="C">.</span>
      <span class="E"></span>
    </span>
  </span>
</p>

我遇到两个问题: (1) 不想对开场 < a> 和闭场 < /a> 之间的任何事情采取行动。我试图完全排除锚元素和其中的任何内容。 (2) 我运行的正则表达式作用于innerhtml,而不是文本节点,因为我使用替换操作将找到的术语包装在span 类中,如下所示:< span class=”xxxx ”>{match}。 因此,例如,在上面的 html 中,假设我搜索术语“指令”,我想避免在此锚元素内匹配。

    <a class="Citation" title="Go to item" rel="cite" href="/uk/directive/2020/0044">
      <span class="D">
        <span class="C"> Directive 2020/44/UK </span>
      </span>
    </a>

但是我想匹配下面的术语“指令”,因为它不是任何锚元素的后代。

      <span class="C"> UK law which is a directive </span>

也许我的做法是错误的,并且有一些更优雅的方式来做我想做的事情。我真正想做的是在文档文本中搜索某些正则表达式,然后将所有匹配结果包装在新的范围中。我是否点击锚元素的文本内容并不重要,只要我不点击href链接之类的内容即可。我只是很困惑为什么我无论如何排除锚元素,仍然对开始和结束标签之间的内容进行更改,例如href 位。

javascript node.js anchor queryselector
2个回答
0
投票

选择所有非锚元素,迭代其子节点并更改文本节点。 这个问题很难理解,但不清楚锚点内部到底应该改变什么,所以我想子元素也应该改变,在锚点内部添加一个跨度来显示这一点。但更好的是,OP 应该提供更多扩展的输入 HTML 并添加所需的输出。

const p = document.querySelectorAll('*:not(a)')
  .forEach(el => [...el.childNodes]
    .forEach(node => node.nodeType === Node.TEXT_NODE && (node.textContent = node.textContent.replace(/some/g, 'any'))));
<p class="1 2">
  <span class="3">
   some writing here
    <strong class="4">some more here</strong>
  </span>
  <strong class="5">
    <span class="6">
      <span class="7"></span>
      <a class="8" href="#abc" title="TITLE" id="9">some text <span> i am some in an anchor</span></a>
      <span class="10">some text</span>
      <span class="11"></span>
    </span>
    <span class="12"></span>
  </strong>
  hello I am some text
</p>


0
投票

尝试以下操作:

const p=document.querySelector("p"); // selector for top level parent element
[p,...p.querySelectorAll("*:not(a):not(a *)")]
 .forEach(e=>[...e.childNodes]
  .filter(n => n.nodeType == Node.TEXT_NODE)
  .forEach(n=>n.textContent=n.textContent.replace(/some/g,"lots of")));
<div>This "some" should not be changed.
<p class="1 2">But this "some" needs to be replaced.
  <span class="3">
   some writing here
<strong class="4">some more here</strong>
  </span>
  <strong class="5">
<span class="6">
  <span class="7"></span>
  <a class="8" href="#abc" title="TITLE" id="9">some text <i>and some italic text</i></a>
  <span class="10">some text</span>
  <span class="11"></span>
</span>
<span class="12"></span>
  </strong>
  hello I am some text
</p>
</div>

从父

<p>
元素开始,
.querySelectorAll("*:not(a)")
集合将包含所有非
a
元素。然后进一步处理这些元素中每一个的子节点内的文本节点。在每个
.textContent
中,字符串“some”将被“lots of”替换。

1。更新:
虽然 OP 提供的 HTML 并不严格要求它,但如果我们想在

*:not(a):not(a *)
标签中排除 anything,@mykaf 建议的选择器
<a>
(请参阅问题下的评论)是必要的。

2。更新:
在 OP 更新了他们的问题之后,现在已经很清楚,其意图是将页面上的任何渲染文本包装在

<span class="xxx">
元素中。

这可以通过在页面主体的

.innerHTML
上应用正则表达式来最轻松地实现:

document.body.innerHTML=document.body.innerHTML.replace(/(?<=>)[^<]+/gm,t=>
 t.replace(/directive/ig,'<span class="xxx">$&</span>'));
.xxx {background-color:#8f8}
<p class="A B">
  <span class="H LegLHS F" id="123">
<span class="D">
  <span class="C">(b)</span>
</span>
  </span>
  <span class="H G LegP3Text">
<a class="LegCitation" title="Go to item" rel="cite" href="/uk/directive/2020/0044">
  <span class="D">
    <span class="C">Directive 2020/44/UK</span>
  </span>
</a>
<span class="D">
  <span class="C"> UK law which is a directive </span>
</span>
<a class="Citation" title="Go to item" rel="cite" href="/uk/directive/2020/0044">
  <span class="D">
    <span class="C"> Directive 2020/44/UK </span>
  </span>
</a>
<span class="D">
  <span class="C">.</span>
  <span class="E"></span>
</span>
  </span>
</p>

© www.soinside.com 2019 - 2024. All rights reserved.