【问题标题】:How to use Javascript to find namespaced HTML elements如何使用 Javascript 查找命名空间的 HTML 元素
【发布时间】:2011-09-28 03:47:18
【问题描述】:

我正在写一些学术性的东西,我在其中命名了 HTML 元素,例如:

<ns:LinkList id="sitesuteis" cssClass="classone">
            <ns:LinkItem id="LI1" href="http://www.ibt.pt/" target="_blank">IBT</ns:LinkItem>
            <ns:LinkItem id="LI2" href="http://http://html5demos.com/t/" target="_blank">HTML5 Demos</ns:LinkItem>
            <ns:LinkItem id="LI3" href="http://diveintohtml5.ep.io/" target="_blank">Dive into HTML5</ns:LinkItem>
            <ns:LinkItem id="LI4" href="http://html5boilerplate.com/" target="_blank">HTML5 Boilerplate</ns:LinkItem>
        </ns:LinkList>

现在,我正在尝试使用 JavaScript:

var elements = document.getElementsByTagName('ns:LinkItem');
element = elements[0];
console.log(element.getAttribute('id'));
//I get a correct value in all browsers

获取我的elements[0] 中的所有子节点。它在所有浏览器中都能正常工作,除了 -IE lt 9-

我试过了:

var children = element.getElementsByTagName('ns:LinkItem');
console.log(children.length);

和:

var children = Array();
for (i=0; i<element.childNodes.length; i++){
   alert(element.childNodes[i].nodeName);
   if (element.childNodes[i].nodeName=="NS:LINKITEM"){
      children.push(element.childNodes[i]);
   }
}
console.log(children.length);

在两个 console.logs 中,除了 Internet Explorer 8 或更低版本,我在每个浏览器中都得到了正确的长度 (4),我得到了 0。

根据@Shadow Wizard,在Internet Explorer 8 及更低版本中,元素的canHaveChildren 属性为false,这意味着死路,浏览器根本不支持此标记的子节点,与@987654328 相同例如,@ 不能有子节点。我试过了,这是真的。如果我尝试:

element.parentNode  

在 Internet Explorer 8 或更低版本中,我得到包含我的标记的 div,而在其他浏览器中,我得到我的父级 &lt;ns:LinkList&gt;

我真的需要一个 hack 来解决这个问题,但我似乎找不到。

【问题讨论】:

  • 什么版本的 IE?有迹象表明 IE 在某些版本中并不总是返回正确的信息。
  • 如果这行正确:var children = element.getElementsByTagName(('xrtml:LinkItem'); 你有一个额外的开头括号,所以我只是想确保这只是一个错字而不是你的代码。
  • 感谢 dtan,这只是一个错字,我编辑了问题
  • 您的示例标记未在您的 LinkItem 节点中显示任何子级。他们在你的实际代码中真的有孩子吗?
  • 你能发布整个html页面吗?我刚用我的 IE8 试了一下,效果很好……检查一下:i51.tinypic.com/3449um9.png

标签: javascript html internet-explorer dom


【解决方案1】:

在 Internet Explorer 8 及更低版本中,元素的 canHaveChildren 属性为 false 意味着死路,浏览器根本不支持此标记的子节点,同样&lt;br /&gt; 不能例如有子节点。

这已在 Internet Explorer 9 中得到修复。

【讨论】:

  • 那么,在 9 之前的版本中没有办法解决这个问题吗?
  • 可能是DTD,但我并没有真正研究过。
【解决方案2】:

在非 Internet Explorer 浏览器中,我建议使用 getElementsByTagNameNS 来获取特定命名空间中的元素。

在 Internet Explorer 中,您可以改用 XPath。

jQuery 还提供了一种使用命名空间的方法;它似乎包含在“jQuery XML parsing with namespaces”中。

【讨论】:

  • 谢谢,我的问题完全出在 IE 上,我必须在 html+javascript 的范围内执行此操作。用 xslt 做不到
  • 相信我,XPath 正是您所需要的。看看这两个链接:developer.mozilla.org/en/…stackoverflow.com/questions/529556/…
  • @André,您所说的“在 html+javascript 范围内”是什么意思 - 在 IE 中,您可以在 javascript/jscript 中使用 xpath(随便)
  • 你有没有得到任何结果/错误?
【解决方案3】:

我从来没有遇到过这个问题,所以这只是一个建议或提示。

我为 MSIE 命名空间“限制”找到了“getElementsByTagName (W3C DOM Core method)”。

我终于在“XPath in JavaScript, Part 3”中找到了可以确认使用 XPath 的要点:

默认情况下,Internet Explorer 的 XPath 引擎无法使用 命名空间(与 DOM Level 3 XPath 实现相同)。 命名空间信息必须提前指定为 XML DOM 文档对象本身。考虑以下 XML 代码:

<books xmlns:wrox="http://www.wrox.com/"
xmlns="http://www.amazon.com/">
    <wrox:book>Professional JavaScript</book> </books>

为了在本文档上使用 XPath 查询,您首先需要 为 wrox 和默认命名空间定义命名空间信息。你 可以通过 setProperty() 方法,传入 "SelectionNamespaces" 和一个空格分隔的命名空间字符串 声明。示例:

xmldoc.setProperty("SelectionNamespaces",
    "xmlns:wrox='http://www.wrox.com/' xmlns='http://www.amazon.com/'"); var book =
xmldoc.documentElement.selectSingleNode("wrox:book");

请注意,命名空间声明的格式与它们相同 出现在 XML 中。不幸的是,没有自动提取的方法 文档中用于 XPath 的命名空间信息 查询。结论

Internet Explorer 确实支持 XPath,但它附带了几个 警告。首先是 XPath 查询仅适用于 XML 文档,而不适用于 在 HTML 文档上,因此不能在文档上用于帮助查找 页面上的元素。二、XPath实现非常基础 并且只允许基本的返回类型(节点和 NodeSet 对象)。仍然, 如果您正在处理 XML 数据,XPath 仍然是一种快速方便的 无需手动遍历 DOM 即可找到特定元素的方法。

【讨论】:

    【解决方案4】:

    这是一个 hack,但它可能足以满足您的需要:

    function getElementsByTagName(parent, tagName)
    {
        if(typeof parent.canHaveChildren === 'undefined' || parent.canHaveChildren)
        {
            return parent.getElementsByTagName(tagName);
        }
    
        var elements = [];
        var cursor = parent;
        while(cursor.nextSibling && cursor.nextSibling.tagName !== ('/' + parent.tagName))
        {
            if(cursor.tagName === tagName.toUpperCase())
            {
                elements.push(cursor);
            }
            cursor = cursor.nextSibling;
        }
        return elements;
    }
    
    function getText(parent)
    {
        return parent.innerHTML || parent.nextSibling.data;
    }
    

    例如:

    var element = document.getElementById('sitesuteis');
    var children = getElementsByTagName(element, 'ns:LinkItem');
    console.log(children.length);
    
    for(var i = 0; i < children.length; i++)
    {
        console.log([getText(children[i]), children[i].getAttribute('href')]);
    }
    

    【讨论】:

    • 查看代码,似乎绝对完美。我今天要试一试。谢谢
    • @André Alçada Padez:仅当您没有嵌套列表时,否则它会在第一个关闭 LinkList 标记处停止。这可以通过跟踪打开/关闭 parent.tagName 标签来解决。
    【解决方案5】:

    我相信以下功能应该可以工作 - 我在以前的项目中使用过它,并且我相信它在 Internet Explorer 6、7 和 8 中有效。我没有在 Internet Explorer 中测试的好方法9,但我猜它应该可以正常工作,如Internet Explorer 9 supports getElementsByTagNameNS。它非常简单,并且依赖于核心浏览器方法。

    /**
     * Cross-browser implementation for namespaced tags
     * @param {DOM Node} n          Parent node
     * @param {String} tag          Tag name you're trying to retrieve
     * @param {String} [ns]         Namespace prefix
     */
    getElementsByTagName = function(n, tag, ns) {
        // map the namespace prefix to the full namespace URIs
        var nsMap = {
            'svg': 'http://www.w3.org/2000/svg'
            // etc - whatever's relevant for your page
        };
        if (!ns) {
            // no namespace - use the standard method
            return n.getElementsByTagName(tag);
        }
        if (n.getElementsByTagNameNS && nsMap[ns]) {
            // function and namespace both exist
            return n.getElementsByTagNameNS(nsMap[ns], tag);
        }
        // no function, get with the colon tag name
        return n.getElementsByTagName(ns + ':' + tag);
    };
    
    // get a list of svg:circle elements
    getElementsByTagName(document, 'circle', 'svg');
    

    这里唯一的痛点是需要定义从命名空间前缀到完整命名空间 URI 的映射。如果你想让它成为一个更便携的函数,你可以让 nsMap 成为一个函数参数,而不是在函数体中定义的东西;或者您可以在全局上下文中引用命名空间映射对象。

    这是一个完全模块化的版本,getElementsByTagName 的版本稍微紧凑:

    var namespaces = (function() {
        var nsMap = {};
    
        /**
         * Add a new XML namespace with prefix
         * @param {String} prefix       Prefix for new namespace
         * @param {String} uri          Full URI of new namespace
         */
        function addNamespace(prefix, uri) {
            nsMap[prefix] = uri;
        }
    
        /**
         * Cross-browser implementation for namespaced tags
         * @param {DOM Node} [n]        Parent node
         * @param {String} tag          Tag name you're trying to retrieve
         * @param {String} [ns]         Namespace prefix
         */
        function getElementsByTagName(n, tag, ns) {
            return !ns ?
                n.getElementsByTagName(tag) :
                (n.getElementsByTagNameNS && nsMap[ns]) ?
                    n.getElementsByTagNameNS(nsMap[ns], tag) :
                    n.getElementsByTagName(ns + ':' + tag);
        }
    
        return {
            addNamespace: addNamespace,
            getElementsByTagName: getElementsByTagName
        };
    }());
    
    // set the svg namespace
    namespaces.addNamespace('svg', 'http://www.w3.org/2000/svg');
    // get a list of svg:circle elements
    namespaces.getElementsByTagName(document, 'circle', 'svg');
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-10-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多