如何使用Javascript查找带名称空间的HTML元素

如何使用Javascript查找带名称空间的HTML元素,javascript,html,internet-explorer,dom,Javascript,Html,Internet Explorer,Dom,我正在写一些学术性的东西,其中我有名称空间的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:/

我正在写一些学术性的东西,其中我有名称空间的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>
获取我的
元素[0]
中的所有子节点。除了-IE lt 9之外,它在所有浏览器中都可以正常工作-

我试过:

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

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


我真的需要对此进行破解,但我似乎找不到。

在Internet Explorer 8及以下版本中,元素的
canHaveChildren
属性是
false
,这意味着死胡同,浏览器根本不支持此标记具有子节点,就像

不能具有子节点一样


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

在非Internet Explorer浏览器中,我建议
getElementsByTagnames
获取特定命名空间中的元素

在Internet Explorer中,可以使用XPath


jQuery还提供了一种使用名称空间的方法;它似乎包含在“.

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

我找到了MSIE命名空间“限制”的“”

我最终在“”中找到了一点,这一点可以确认XPath的使用是:

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

<books xmlns:wrox="http://www.wrox.com/"
xmlns="http://www.amazon.com/">
    <wrox:book>Professional JavaScript</book> </books>
请注意,命名空间声明的格式与它们相同 显示在XML中。不幸的是,没有自动提取的方法 文档中用于XPath的命名空间信息 查询。结论

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


这是一个黑客,但它可能足够健壮,满足您的需要:

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')]);
}
var-element=document.getElementById('sitesuteis');
var children=getElementsByTagName(元素'ns:LinkItem');
console.log(childrence.length);
对于(变量i=0;i
我相信以下功能应该可以工作-我在以前的项目中使用过它,我相信它在Internet Explorer 6、7和8中可以有效工作。我没有一个很好的方法来测试InternetExplorer9,但我猜它应该可以正常工作。它非常简单,并且依赖于核心浏览器方法

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

什么版本的IE?som表示IE在某些版本中并不总是返回正确的信息。如果此行正确:
var children=element.getElementsByTagName(('xrtml:LinkItem'))
您有一个额外的开始部分,所以我只想确定这只是一个输入错误,而不是您的代码。谢谢dtan,这只是一个输入错误,我编辑了问题您的示例标记在您的LinkItem节点中没有显示任何子项。它们在您的实际代码中是否确实有子项?您可以发布整个html页面吗?我只是用我的IE8成功了…检查一下:那么,在9之前的版本中没有解决这个问题的方法吗?也许是使用
DTD
的方法,但我没有真正研究它。谢谢,我的问题完全是IE的,我必须在html+javascript的范围内完成。不能使用XSLT相信我,XPath是你需要的。看看那些两个链接:@André,你所说的“html+javascript领域内”是什么意思?在IE中,你可以在javascript/jscript中使用xpath(无论什么)你得到任何结果/错误了吗?看看代码,看起来绝对完美。我今天要试试。thanks@AndréAlçada Padez:仅当您没有嵌套列表时,否则它会在第一个结束链接列表标记上停止。这可以通过跟踪打开/关闭parent.tagName标记来解决。
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')]);
}
/**
 * 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');
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');