如何使用 Javascript 查找命名空间 HTML 元素

发布于 2024-11-18 21:16:43 字数 1824 浏览 3 评论 0原文

我正在写一些学术性的东西,其中有命名空间的 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] 中的所有 ChildNode。它在所有浏览器中工作正常,除了 -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 中,我在每个浏览器中都得到了正确的长度(4),除了 Internet Explorer 8 或更少,我得到 0。

根据@Shadow向导,在 Internet Explorer 8 及更低版本中,元素的 canHaveChildren 属性为 false,这意味着死胡同,浏览器根本不支持此标记的子节点,与 < 相同;br例如,/> 不能有子节点。我试过了,确实如此。如果我尝试:

element.parentNode  

在 Internet Explorer 8 或更低版本中,我会得到包含我的标记的 div,而在其他浏览器中,我会得到我的父级

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

I am writing something academic where I have namespaced HTML elements like:

<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>

Now, in JavaScript I am trying:

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

to get all the ChildNodes in my elements[0]. It works fine in all browsers, except -IE lt 9-

I tried:

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

and:

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);

In both console.logs, I get the correct length (4) in every browser except Internet Explorer 8 or less where I get 0.

According to @Shadow Wizard, in Internet Explorer 8 and below, the canHaveChildren property of the element is false which means dead end, the browser simply doesn't support having child nodes for this tag, same way that <br /> can't have child nodes for example. I have tried it and it is true. If I try:

element.parentNode  

in Internet Explorer 8 or less, I get the div that contains my markup and in the other browsers I get my parent <ns:LinkList>.

I really need a hack for this, and I can't seem to find one.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

落花浅忆 2024-11-25 21:16:43

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

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

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

In non-Internet Explorer browsers, I would recommend getElementsByTagNameNS to get the elements in a specific namespace.

In Internet Explorer, you can use XPath instead.

jQuery also provides a way to use namespaces; it seems to be covered in "jQuery XML parsing with namespaces".

苏大泽ㄣ 2024-11-25 21:16:43

我相信以下功能应该有效 - 我在之前的项目中使用过它,并且我相信它在 Internet Explorer 6、7 和 8 中有效地工作。我没有在 Internet Explorer 9 中测试的好方法,但是我猜它应该可以正常工作,如 Internet Explorer 9 支持 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');

I believe the following function should work - I've used it in a previous project, and I believe it works effectively in Internet Explorer 6, 7, and 8. I don't have a good way to test in Internet Explorer 9, but I'm guessing it should work properly, as Internet Explorer 9 supports getElementsByTagNameNS. It's pretty straightforward, and relies on core browser methods.

/**
 * 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');

The only pain point here is the requirement to define a mapping from the namespace prefix to the full namespace URI. If you want to make this a more portable function, you could have nsMap be a function argument, rather than something defined in the function body; or you could refer to a namespace map object in the global context.

Here's a fully modularized version, with a slightly tighter version of 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');
方觉久 2024-11-25 21:16:43

在 Internet Explorer 8 及更低版本中,元素的 canHaveChildren 属性为 false 这意味着死胡同,浏览器根本不支持此标记具有子节点,同样的方式例如,
不能有子节点。

不过,此问题已在 Internet Explorer 9 中得到修复。

In Internet Explorer 8 and below, the canHaveChildren property of the element is false which means dead end, the browser simply doesn't support having child nodes for this tag, same way that <br /> can't have child nodes for example.

This has been fixed in Internet Explorer 9 though.

时光沙漏 2024-11-25 21:16:43

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

我发现 MSIE 命名空间“限制”的“getElementsByTagName(W3C DOM 核心方法)”。

我终于在“XPath中找到了要点JavaScript,第 3 部分”将确认 XPath 的使用,这将是重点:

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

<书籍 xmlns:wrox="http://www.wrox.com/"
xmlns="http://www.amazon.com/">
    专业 JavaScript 

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

xmldoc.setProperty("SelectionNamespaces",
    “xmlns:wrox='http://www.wrox.com/' xmlns='http://www.amazon.com/'”);变量书 =
xmldoc.documentElement.selectSingleNode("wrox:book");

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

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

I never had this issue, so this is rather just a proposal or hint.

I found "getElementsByTagName (W3C DOM Core method)" for MSIE namespace "restriction".

I finally found the point in "XPath in JavaScript, Part 3" that would confirm XPath use would be the point:

By default, Internet Explorer’s XPath engine doesn’t work with
namespaces (the same as the DOM Level 3 XPath implementation).
Namespace information must be specified ahead of time as a property on
the XML DOM document object itself. Consider the following XML code:

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

In order to use XPath queries on this document, you’d first need to
define namespace information for the wrox and default namespaces. You
can do so via the setProperty() method, passing in
"SelectionNamespaces" and a space-separated string of namespace
declarations. Example:

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

Note that the namespace declarations are in the same format as they
appear in the XML. Unfortunately, there is no automatic way to extract
the namespace information from the document for use with XPath
queries. Conclusion

Internet Explorer does have XPath support, but it comes with several
caveats. First is that XPath queries only work on XML documents, not
on HTML documents and therefore can’t be used on document to help find
elements on the page. Second, the XPath implementation is very basic
and allows only basic return types (nodes and NodeSet objects). Still,
if you’re dealing with XML data, XPath remains a fast and convenient
way to find specific elements without walking the DOM manually.

愁以何悠 2024-11-25 21:16:43

这是一个 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')]);
}

This is a hack, but it might be robust enough for what you need:

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;
}

For example:

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')]);
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文