【问题标题】:Extract single element from XMLHttpRequest从 XMLHttpRequest 中提取单个元素
【发布时间】:2010-04-10 18:00:03
【问题描述】:

我实际上正在制作一个侧边栏小工具(基于 AJAX),并且我正在寻找一种从 AJAX 请求中提取单个元素的方法。

我发现的唯一方法就是这样做:

var temp = document.createElement("div");
temp.innerHTML = HttpRequest.innerText;
document.body.appendChild(temp);
temp.innerHTML = document.getElementByID("WantedElement").innerText;

但它非常难看,我想直接从请求中提取 WantedElement 而不将其添加到实际文档中......

谢谢!

【问题讨论】:

    标签: javascript ajax windows-desktop-gadgets


    【解决方案1】:

    如果您可以控制数据,那么您的处理方式可能是最好的方法。这里的其他答案有它们的好处,但它们也都有相当大的缺陷。例如,querySelector() 方法仅适用于在主机上以 IE8 模式运行的 Windows 桌面小工具。正则表达式对于解析 HTML 尤其不可靠,不应使用。

    如果您无法控制数据,或者数据未通过安全协议传输,则您应该更关注安全性而不是代码美学 - 您可能会给小工具和主机带来潜在的安全风险机器通过在文档中插入未经处理的 HTML。由于小工具以用户或管理员级别的权限运行,因此明显的安全风险是不受信任的源/MITM 脚本注入,从而为恶意脚本留下一个漏洞,对运行它的机器造成严重破坏。

    一种可能的解决方案是使用htmlfile ActiveXObject:

    function getElementFromResponse(divId)
    {
        var h = new ActiveXObject("htmlfile");
        h.open();
    
        // disable activex controls
        h.parentWindow.ActiveXObject = function () {};
    
        // write the html to the document
        h.write(html);
    
        h.close();
        return h.getElementById("divID").innerText;
    }
    

    您也可以使用 IE8 的 toStaticHTML() 方法,但您的小工具需要在 IE8 模式下运行。

    【讨论】:

    • 谢谢!我总是忘记我不必成为小工具中的跨浏览器,因此我可以使用 ActiveX。
    • @m6a-uds:这可能是开发小工具的最大好处,也是IE专有功能最适合的用途。我内置到小工具中的一些东西不可能在另一个浏览器上运行:-)
    【解决方案2】:

    一种选择是使用正则表达式:

    var str = response.match(/<div id="WantedElement">(.+)<\/div>/);
    str[0]; // contents of div
    

    但是,如果您的服务器响应更复杂,我建议您使用JSON 之类的数据格式作为响应。然后在客户端解析会干净得多。

    【讨论】:

      【解决方案3】:

      您可以将来自 XMLHttpRequest 的响应附加到隐藏的 div 中,然后调用 getElementById 以获取所需的元素。稍后在完成后删除 div。或者,也许可以创建一个为您处理此问题的函数。

      function addNinjaNodeToDOM(html) {
          var ninjaDiv = document.createElement("div");
          ninjaDiv.innerHTML = html;
          ninjaDiv.style.display = 'none';
          return ninjaDiv;
      }
      
      var wrapper = addNinjaNodeToDOM(HttpRequest.innerText);
      var requiredNode = wrapper.getElementById("WantedElement");
      // do something with requiredNode
      document.body.removeChild(wrapper); // remove when done
      

      将它附加到 DOM 的唯一原因是因为 getElementById 除非它是 DOM 树的一部分,否则将无法工作。见MDC

      但是,您仍然可以在分离的 DOM 节点上运行选择器和 XPath 查询。这将使您不必将元素附加到 DOM。

      var superNinjaDiv = document.createElement('div');
      superNinjaDiv.innerHTML = html;
      var requiedNode = superNinjaDiv.querySelector("[id=someId]");
      

      【讨论】:

        【解决方案4】:

        我认为在这种情况下使用 getElementById 来查找元素不是一个好方法。这是因为您必须采取额外的步骤才能使用它。您将元素包装在 DIV 中,注入 DOM,使用 getElementById 查找您的元素,然后从 DOM 中删除注入的 DIV。

        DOM 操作代价高昂,并且注入也可能导致不必要的回流。问题是您有一个 document.getElementById 而不是一个 element.getElementById,它允许您在不注入文档的情况下进行查询。

        要解决这个问题,使用 querySelector 是一个明显的解决方案,而且要容易得多。否则,如果可以并且您的元素已定义类,我建议您使用 getElementsByClassName。

        getElementsByClassName 是在 ELEMENT 上定义的,因此无需在 DOM 中注入元素即可使用。

        希望这会有所帮助。

        【讨论】:

        • @Rajat: querySelector 在 IE7 中不可用,它默认安装在 Vista 中,因此是 Windows 桌面小工具的主机,除非安装了 IE8 并且小工具为 X-UA-Compatible 标头指定 IE8在元标记中。 getElementsByClassName 不受任何当前发布的 IE 版本的支持。
        【解决方案5】:

        通过 AJAX 请求传递 HTML 有点不寻常;通常你传递一个客户端可以直接评估的 JSON 字符串,然后使用它

        话虽如此,我认为没有一种方法可以按照您想要的跨浏览器的方式在 javascript 中解析 HTML,但这里有一种在 Mozilla 衍生产品中执行此操作的方法:

        var r = document.createRange();
        r.selectNode(document.body);
        var domNode = r.createContextualFragment(HTTPRequest.innerText);
        

        【讨论】:

        • @Michael:不幸的是,Windows 桌面小工具在 Internet Explorer 的“服务器”小窗口中运行,因此您的 Mozilla 解决方案在这里没有多大帮助 :-)
        猜你喜欢
        • 1970-01-01
        • 2017-07-21
        • 1970-01-01
        • 2010-10-23
        • 1970-01-01
        • 1970-01-01
        • 2011-05-27
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多