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"/>
Ответы
Ответ 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
.