Подтвердить что ты не робот

Chrome 22 выводит недопустимый XML, когда атрибуты имеют пространство имен xlink

У меня есть минимальный фрагмент JavaScript:

 
var xml = '<El a:title="T" a:href="H" xmlns:a="http://www.w3.org/1999/xlink" />';
var dom = new DOMParser().parseFromString(xml, 'text/xml');
xml = new XMLSerializer().serializeToString(dom);

Когда я выполняю код в большинстве браузеров (просто вставьте его в консоль JavaScript браузера), XML-синтаксический анализ с последовательным интерфейсом эквивалентен оригиналу. Например, в Chrome 8 я получаю:

<El xmlns:a="http://www.w3.org/1999/xlink" a:title="T" a:href="H"/>

Однако в Chrome 22 тот же фрагмент кода изменяет XML на:

<El xmlns:a="http://www.w3.org/1999/xlink" xlink:title="T" xlink:href="H"/>

Обратите внимание, что префикс пространства имен xlink, используемый атрибутами title и href, не определен нигде, поэтому XML теперь недействителен. Как вы, вероятно, можете себе представить, это вызывает всевозможные проблемы для кода, который пытается впоследствии использовать XML.

Является ли это ошибкой в ​​XMLSerializer или мне не хватает некоторых тонкостей о том, как DOM следует сериализовать?

Также кто-нибудь нашел обходное решение, которое я могу поместить в код, в отличие от того, чтобы XML соответствовал очевидному предпочтению использовать xlink в качестве префикса для пространства имен XLink?

Update

Я провел некоторое дополнительное тестирование, и проблема, похоже, вызвана тем фактом, что XMLSerializer распознает пространство имен XLink и настаивает на выводе префикса xlink для него, без должной регистрации этого префикса.

Итак, этот фрагмент работает нормально:

var xml = '<El a:title="T" a:href="H" xmlns:a="any-other-namespace-uri" />';
var dom = new DOMParser().parseFromString(xml, 'text/xml');
xml = new XMLSerializer().serializeToString(dom);

Итак, здесь я изменил URL-адрес пространства имен на что-то менее известное, и результат теперь действителен:

<El xmlns:a="any-other-namespace-uri" a:title="T" a:href="H"/>

Следующий фрагмент также отлично работает:

var xml = '<El a:title="T" a:href="H" xmlns:a="http://www.w3.org/2000/xlink" />';
var dom = new DOMParser().parseFromString(xml, 'text/xml');
xml = new XMLSerializer().serializeToString(dom);

Итак, в этом случае мы используем "ожидаемый" префикс для пространства имен XLink и затем сериализуем без проблем:

<El xmlns:a="http://www.w3.org/2000/xlink" a:title="T" a:href="H"/>
4b9b3361

Ответ 1

Я по-прежнему уверен, что в Chrome XMLSerializer есть ошибка, которая, скорее всего, введена при обращении к SVG-обработке атрибутов XLink, которые Barbarrosa указал на. Но, учитывая отсутствие ответа на отчет об ошибке , который я сделал для этого, нам пришлось двигаться вперед и решать проблему.

Мы работаем над проблемой, вызывая эту функцию на documentElement:

function EnsureXLinkNamespaceOnElement(element)
{
  if (element.nodeType == 1)
  {
    var usesXLinkNamespaceUri = false;
    var hasXLinkNamespacePrefixDefined = false;
    for (var i = 0; i < element.attributes.length; i++) 
    {
      var attribute = element.attributes[i];
      if (attribute.specified)
      {
        if (attribute.name.indexOf("xmlns:xlink") == 0) 
        {
          hasXLinkNamespacePrefixDefined = true;
        } 
        else if (attribute.namespaceURI == "http://www.w3.org/1999/xlink")
        {
          usesXLinkNamespaceUri = true;
        }
      }
    }
    if (usesXLinkNamespaceUri && !hasXLinkNamespacePrefixDefined)
    {
      element.setAttribute('xmlns:xlink', 'http://www.w3.org/1999/xlink');
    }

    for (i = 0; i < element.childNodes.length; i++)
    {
      EnsureXLinkNamespaceOnElement(element.childNodes[i]);
    }
  }
}

Функция просто гарантирует, что атрибут xmlns:xlink объявлен для любого элемента, который был приписан в пространстве имен XLink. Поскольку функция обходит дерево и, следовательно, может быть довольно трудоемкой, я вызываю ее только для версий версии 22 и выше.

Обратите внимание, что в большинстве случаев вам также может быть просто просто добавить пространство имен xmlns:xlink в элементе документа, так как оно будет унаследовано оттуда. Но в нашем случае был некоторый другой код, который разбивает элемент документа с помощью регулярного выражения, поэтому мы решили безопасно играть и просто добавлять атрибут везде, где это может понадобиться.

Обновление (20130324):

Ошибка была исправлена ​​и проверена в Chrome Canary 26. Я тоже смог проверить ее на версии 25.0.1364.172 m.