HTML-элементы пространства имен Javascript - PullRequest
5 голосов
/ 04 июля 2011

Я пишу что-то академическое, где у меня есть 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

пытается получить все дочерние узлы в моих элементах [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, я получаю правильную длину (4) в каждом браузере, кроме IE8 или меньше, я получаю 0.

Согласно @Shadow Wizard В IE8 и ниже свойство canHaveChildren элемента имеет значение false, что означает тупик - браузер просто не поддерживает наличие дочерних узлов для этого тега, так же, как
не может есть дочерние узлы, например. Я попробовал это, и это правда. Если я попытаюсь:

element.parentNode  

в IE 8 или менее, я получаю div, который содержит мою разметку, а в других браузерах я получаю своего родителя

Мне действительно нужен хак для этого, и я не могу его найти.

Ответы [ 5 ]

1 голос
/ 12 июля 2011

Я полагаю, что следующая функция должна работать - я использовал ее в предыдущем проекте и считаю, что она эффективно работает в IE6, IE7 и IE8. У меня нет хорошего способа тестирования в IE9, но я предполагаю, что он должен работать правильно, так как IE9 поддерживает 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');
1 голос
/ 07 июля 2011
  • В браузерах, отличных от IE, я бы рекомендовал getElementsByTagNameNS , чтобы получить элементы в определенном пространстве имен

  • В IE вы можете использовать XPath вместо

РЕДАКТИРОВАТЬ : JQuery также предоставляет способ использования пространств имен; Кажется, что он покрыт здесь .

1 голос
/ 04 июля 2011

В IE8 и ниже свойство canHaveChildren элемента равно false, что означает тупик - браузер просто не поддерживает наличие дочерних узлов для этого тега, так же как у <br /> не может быть дочернего элемента узлы например.

Это было исправлено в IE9.

0 голосов
/ 11 июля 2011

Такой взлом, но может быть достаточно надежным для того, что вам нужно:

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')]);
}
0 голосов
/ 11 июля 2011

Никогда не получал эту проблему, как головная боль .. так что это скорее всего лишь предложение или подсказка.

EDIT1: удалено предыдущее предложение для прототипа getElementsByTag, поскольку оно просто не соответствует теме.

EDIT2: в btwn я нашел это подтверждение для пространства имен MSIE "ограничение".

EDIT3: я наконец нашел точку здесь , которая подтверждает, что использование Xpath будет точкой:

По умолчанию механизм XPath Internet Explorer не работает с пространства имен (аналогично реализации XPath для DOM уровня 3). Информация о пространстве имен должна быть указана заранее как свойство сам объект документа XML DOM. Рассмотрим следующий XML-код:

Профессиональный JavaScript

Чтобы использовать запросы XPath к этому документу, вам сначала необходимо определить информацию о пространстве имен для пространств имен wrox и по умолчанию. Вы может сделать это через метод setProperty (), передав «SelectionNamespaces» и разделенная пробелами строка пространства имен деклараций. Пример:

xmldoc.setProperty ( "SelectionNamespaces", "xmlns: wrox = 'http://www.wrox.com/' xmlns =' http://www.amazon.com/'"); var book = xmldoc.documentElement.selectSingleNode ( "Wrox: книга");

Обратите внимание, что объявления пространства имен имеют тот же формат, что и появляются в XML. К сожалению, нет автоматического способа извлечь информация о пространстве имен из документа для использования с XPath запросы. Заключение

Internet Explorer поддерживает XPath, но поставляется с несколькими предостережения. Во-первых, запросы XPath работают только с документами XML, а не с в документах HTML и поэтому не могут быть использованы в документе, чтобы помочь найти элементы на странице. Во-вторых, реализация XPath является очень простой и разрешает только базовые типы возврата (узлы и объекты NodeSet). Еще, если вы имеете дело с данными XML, XPath остается быстрым и удобным способ найти конкретные элементы без обхода DOM вручную.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...