最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

How to use Javascript to find namespaced HTML elements - Stack Overflow

programmeradmin7浏览0评论

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

<ns:LinkList id="sitesuteis" cssClass="classone">
            <ns:LinkItem id="LI1" href="/" target="_blank">IBT</ns:LinkItem>
            <ns:LinkItem id="LI2" href="http:///" target="_blank">HTML5 Demos</ns:LinkItem>
            <ns:LinkItem id="LI3" href="/" target="_blank">Dive into HTML5</ns:LinkItem>
            <ns:LinkItem id="LI4" href="/" 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.

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./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./" 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.

Share Improve this question edited Feb 4, 2020 at 7:46 the Tin Man 161k44 gold badges221 silver badges306 bronze badges asked Jul 4, 2011 at 13:12 André Alçada PadezAndré Alçada Padez 11.6k26 gold badges71 silver badges128 bronze badges 5
  • What version(s) of IE? There is som indication that IE does not always return correct information in some versions. – Schroedingers Cat Commented Jul 4, 2011 at 13:15
  • if this line correct: var children = element.getElementsByTagName(('xrtml:LinkItem'); you have an extra opening parens, so i just wanted to make sure that's just a typo here and not your code. – hellatan Commented Jul 4, 2011 at 13:23
  • thanks dtan, that was just a typo, i edited the question – André Alçada Padez Commented Jul 4, 2011 at 13:53
  • 1 Your example markup doesn't show any children in your LinkItem nodes. Do they actually have children in your actual code? – Jani Hartikainen Commented Jul 11, 2011 at 9:53
  • could you post the whole html page? I just tried with my IE8 and it worked... check it: i51.tinypic./3449um9.png – Clash Commented Jul 12, 2011 at 20:34
Add a ment  | 

5 Answers 5

Reset to default 2

In non-Internet Explorer browsers, I would remend 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".

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/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/2000/svg');
// get a list of svg:circle elements
namespaces.getElementsByTagName(document, 'circle', 'svg');

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.

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./"
xmlns="http://www.amazon./">
    <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./' xmlns='http://www.amazon./'"); 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 es 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.

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')]);
}
发布评论

评论列表(0)

  1. 暂无评论