【问题标题】:Replace html element stored as a string using partial使用部分替换存储为字符串的html元素
【发布时间】:2018-03-04 08:16:07
【问题描述】:

我正在使用 node.js 从 API 中提取 html,在显示之前将其存储在变量中。 我需要替换该 html 字符串中的链接,但我只能使用链接的前面部分进行搜索,因为它们是动态的。

我找到了一个使用document.querySelectorAll("a[href^='http://somelink.com/12345678']") 的示例

Javascript getElement by href?

但我没有使用 DOM。

需要删除/替换的动态链接:

<a href="http://somelink.com/12345678-asldkfj>Click Here</a>
<a href="http://somelink.com/12345678-clbjj>Click Here</a>
<a href="http://somelink.com/12345678-2lksjd>Click Here</a>

我可以搜索的内容:

<a href="http://somelink.com/12345678

我需要更改实际链接名称“单击此处”或删除该元素。

有什么想法可以用普通的 JS 来实现吗? 最初我在想也许有一种方法可以创建一个假/临时 DOM?

编辑: 用我的代码修改下面的答案,它完全符合我的需要。

var str = '<a href="http://somelink.com/12345678-asldkfj">Click Here</a><a href="http://somelink.com/12345678-clbjj">Click Here</a><a href="http://somelink.com/12345678-2lksjd">Click Here</a>';
var div = document.createElement("div");
div.innerHTML = str;

var links = div.querySelectorAll("a[href^='http://somelink.com/12345678']");

for(i=0; i<links.length; i++) {
    if(links[i]) {
        str = str.replace(links[i].outerHTML, 'New Name');
  }
}

console.log(str);

【问题讨论】:

    标签: javascript html node.js string dom


    【解决方案1】:

    你什么也得不到,因为你的链接href属性没有正确结束,最后缺少",如果你修复它,一切都会好起来的。

    否则,如果您不使用 HTML 和 DOM,则可以将 HTML 字符串附加到临时 DOM 元素中,如下所示:

    var str = '  <a href="http://somelink.com/12345678-asldkfj">Click Here</a>'
    +'<a href="http://somelink.com/12345678-clbjj">Click Here</a>'
     + '<a href="http://somelink.com/12345678-2lksjd">Click Here</a>';
     var div = document.createElement("div");
     div.innerHTML = str;
    
    var links = div.querySelectorAll("a[href^='http://somelink.com/12345678']");
    console.log(links);

    注意:

    要在nodejs 环境中使用此代码,您需要使用DOM 解析器模块,这些模块可以帮助您:

    【讨论】:

    • 谢谢,这会起作用,然后我可以做一个 str = str.replace(links[i].outerHTML, '');彻底清除链接。其他人说不要使用临时 DOM 元素。
    • @user3712837 在这种情况下,您将需要str = str.replace(links, '');,它将一起删除所有链接,或者您可以循环链接并单独删除它们。
    • 一个问题是我正在使用节点并且没有文档。
    • 那么,你需要在 nodejs 中使用 DOM 模块 ;)
    • 哈哈,谢谢,我刚把它放进去,看起来它正在工作。从下面的答案中使用 JSDOM。
    【解决方案2】:

    您可以使用字符串搜索或正则表达式 (but shouldn't unless extremely simple html) 来尝试操作您的 html 字符串。但是您可以并且更容易导入创建 DOM 解析/操作方法的包,例如 Cheerio(类似 jQuery)或 jsDOM

    从那里您可以将字符串解析为 DOM 文档,通过它们的方法查询和替换文本或删除元素。

    jsDOM 示例:

    const JSDOM = require("jsdom");
    const dom = new JSDOM(yourHtmlString);
    const document = dom.window.document;
    
    var elements = document.querySelectorAll("a[href^='http://somelink.com/12345678']");
    
    for(let i=0; i<elements.length; i++){
      elements[i].textContent = "Replacement text";
      //element.remove() if removing
    }
    
    var resultHtml = dom.serialize();
    

    欢呼示例:

    var cheerio = require('cheerio');
    $ = cheerio.load(yourHtmlString);
    
    $("a[href^='http://somelink.com/12345678']").text('Text to Replace "Click Here"');
    //or .remove() if wanting to remove
    
    var htmlResult = $.html();
    

    【讨论】:

      【解决方案3】:

      在这里,一个假冒的 dom 将是严重的过度杀戮。您只需要一个字符串替换。如果你确定你的字符串是安全的,那么这个例子就足够了。

      编辑:添加了解析 html 字符串以生成要处理的链接数组并添加了 innerText 的替换。

      从 html 字符串中获取链接数组:

      • 匹配&lt;a,后跟0个或多个而不是&gt;,后跟&gt;,后跟匹配其余部分的最短可能字符串,然后是&lt;/a&gt;

      • 此模式包括用于开始/结束标记的捕获组,因为这样我们以后可以重复使用相同的模式来替换锚点的 innerText。

      替换每个链接的href:

      • 匹配href=",后跟1个或多个不是",后跟"
      • 将完整匹配替换为href=",后跟新网址,然后是"

      替换anchor的innerText:

      • 匹配(&lt;a,后跟 0 个或多个而不是 &gt;,后跟 &gt;),然后是匹配其余部分的最短可能字符串,然后是(&lt;/a&gt;),捕获开始标记$1 和 $3 中的结束标记。
      • 用开始标签替换字符串,然后是新文本,然后是结束标签。

      const linksHtml = document.querySelector('#links').innerHTML
      
      // Note that capture group 2 will not actually capture "shortest string" even 
      // though it matches. $2 in a replace() would return huge useless string.
      
      const anchorPattern =/(<a[^>]*>)(.*?)(<\/a>)/g
      
      const links = linksHtml.match(anchorPattern)
      
      const newUrls = [
        'http://someotherlink.com/cool',
        'http://someotherlink.com/happy',
        'http://someotherlink.com/smile'
      ]
      
      const newText = [
        'Cool',
        'Happy',
        'Smile',
      ]
      
      const replaced = links
        // replace urls
        .map( (link, i) =>
          link.replace(/(href=")[^"]+"/, `$1${newUrls[i]}"`)
        )
        // replace innerText
        .map( (link, i) =>
          link.replace(anchorPattern, `$1${newText[i]}$3`)
        )
      
      document.querySelector('pre')
        .innerText = JSON.stringify(replaced,null,2)
      <div id="links">
        <h2>Probably will be a header.</h2>
        <a href="http://somelink.com/12345678-asldkfj">Click Here</a>
        <p>And maybe some random text.</p>
        <a href="http://somelink.com/12345678-clbjj">Click Here</a>
        <p>One of the links might be in a paragraph. <a href="http://somelink.com/12345678-2lksjd">Click Here</a></p>
      </div>
      
      <h2>Result: </h2>
      <pre/>

      【讨论】:

      • 这真的很有帮助,有什么方法可以更改该链接的“单击此处”部分或完全删除它?但是,您拥有的链接数组只是一个大的 html 字符串,我没有像那样将它们拉出来。
      • 更新了答案。里面有all。 ?
      • 感谢您再次修改。似乎它正在替换所有链接,我只需要某些情况。 @chsdk 确实有效,只是使用了 jsDOM,但可能像你建议的那样过度杀戮。
      • 是的,它正在替换所有链接,因为我对其进行了编码以替换所有链接。我不知道确切你需要什么,所以我写了一个通用示例来为你提供所需的技术。研究这里实际发生的事情,然后根据您的用例进行调整。您可以从只解析您想要处理的链接开始,而不是所有链接,或者您可以使用Array.prototype.filter() 来拆分您真正想要更改的链接。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-11-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-01-15
      • 2023-02-22
      • 1970-01-01
      相关资源
      最近更新 更多