【问题标题】:Filtering HTML comment nodes from innerHTML从 innerHTML 过滤 HTML 注释节点
【发布时间】:2014-01-04 21:02:04
【问题描述】:

我想知道是否有一种方法可以过滤 DOM 的 innerHTML 以仅包含实际的 HTML 并丢弃所有评论节点?


实际上,我正在使用 Angularjs 并使用 Selenium 编写一些测试。 Angular 会在渲染的 HTML 中乱扔很多 cmets,例如:

<!-- ngSwitchWhen: join -->
<div data-ng-switch-when="leave">
  <!-- ngIf: isNow -->
  .
  .
  .
</div>

我目前正在尝试匹配结果:@client 是 WebDriver 实例。

@client.findElement(By.xpath("//*[@id='log']/li")).getAttribute('innerHTML').then (innerHtml) ->
      html = innerHtml.trim()
      expect(html).to.equal """
        <div class="image"><i class="icon-refresh"></i></div>
        <div class="fade-6 content">Getting more activities...</div>
      """

当我尝试使用 Mocha 测试返回的 DOM 结构时,这会产生一个大问题。我要测试什么?我不可能在我的期望值中重复所有无用的 cmets,这将是非常浪费的。

有没有更好的办法?

【问题讨论】:

    标签: javascript html angularjs selenium


    【解决方案1】:

    编写依赖于innerHTML 的测试根本不是一个好主意。

    当您获取innerHTML 时,浏览器会将 DOM 中的信息序列化为一个新的标记字符串,该标记字符串不一定与最初解析为 DOM 的标记相同。

    标记详细信息,例如:

    • 有哪些订单属性
    • 案例标签是什么
    • 标签中有什么空格
    • 哪些引号用于分隔属性值
    • 哪些内容字符被编码为实体或字符引用

    不存储在 DOM 信息集中,因此不保留。不同的浏览器可以并且将产生不同的输出。在某些情况下,IE 甚至会返回无效标记,或者在解析时不会返回到相同信息集的标记。

    +1 katspaugh 的回答展示了从 DOM 中获取信息的方法,而不是依赖 innerHTML,从而避免了这个问题。

    但是,更一般地说,编写强烈依赖于应用程序使用的确切标记的测试通常不是一个好主意。这是测试中的需求和实现细节之间过于紧密的耦合。而且,即使是微不足道的文体原因或文本更新,您对标记所做的任何微小更改都意味着您必须更新所有测试以匹配。测试是一个有用的工具,可以捕捉到你不想破坏的东西;每次更改都会中断的测试不会向您提供有关您是否破坏了某些内容的反馈,因此没有用处。

    虽然通常没有灵丹妙药将测试与应用程序标记完全分开,但通常您应该将测试减少到满足用户要求的最低限度,并添加信号以捕获这些情况。我不知道你的应用到底在做什么,但我猜这个要求是这样的:“当用户点击‘更多’按钮时,应该出现一个忙碌的微调器,让他们知道正在获取信息”。

    要对此进行测试,您可以进行类似“id 为 'log' 的元素是否包含具有类 'icon-refresh' 的元素?”之类的检查。如果您想更具体地说明它是一个与获取活动有关的微调器,您可以将“刷新活动”之类的类添加到“获取更多活动...” div,并使用该类检测元素而不是依赖可能会更改的文本(特别是如果您曾经翻译过您的应用)。

    【讨论】:

      【解决方案2】:

      如您所知,评论节点是 DOM 节点。您可以遍历所有节点并通过它们的node type 过滤掉 cmets:

      recursivelyIterate(container, function (subNode) {
          if (subNode.nodeType == Node.COMMENT_NODE) {
              subNode.parentNode.removeChild(subNode);
          }
      });
      

      (我没有包含recursivelyIterate函数的代码,但写一个应该很简单。)


      或者,让 cmets 与 DOM 节点一起工作,不与 DOM 节点一起工作,与 DOM 元素一起工作。 getElementsByTagNamequerySelectorAll 和朋友们。

      【讨论】:

      • 感谢直接使用 querySelector* 及其同类的建议。尽管节点中的数据的写入方式仍然存在问题,但我对此很放心。 有些文本是用标签包裹的,有些文本只是……文本。,像这样: &lt;div class='node'&gt;&lt;span class='wrap1'&gt;Text1&lt;/span&gt; is not equal to &lt;span class='wrap2'&gt;Text2&lt;/span&gt;&lt;/div&gt;

        现在当我得到 @ 的孩子时987654329@ 并过滤它们,我得到了节点,但不是带有is not equal to 文本的文本节点。有什么指点吗?
      • @KumarHarsh,请记住,您可以检查节点类型并将其与Node.COMMENT_NODENode.TEXT_NODENode.ELEMENT_NODE 之一进行比较。文本节点和元素节点都是具有不同类型的独立节点。
      • 是的,我知道,但似乎 DOM 元素(div、span 等)之外的文本不是其父元素的子元素...:? 对不起,这里我无法准确解释,请看这个小提琴: jsfiddle.net/RedDevil/9vVZj Shouldn't I be Included 文本应该形成一个单独的 DOM 节点,不是吗?
      • 您应该使用childNodes 而不是children(它们只是元素节点)。见jsfiddle.net/6McQu
      • 就是这样!非常感谢。 :)
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-12-10
      • 2017-08-08
      • 1970-01-01
      • 2021-08-04
      • 1970-01-01
      • 2019-08-17
      • 1970-01-01
      相关资源
      最近更新 更多