24

次の最小限の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は元のXMLと同等です。たとえば、Chrome8では次のようになります。

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

xlinktitle属性とhref属性で使用される名前空間プレフィックスはどこにも定義されていないため、XMLは無効になっていることに注意してください。ご想像のとおり、これにより、後でXMLを使用しようとするコードにあらゆる種類の問題が発生します。

これはXMLSerializerのバグですか、それともDOMのシリアル化方法に関する複雑な点が欠けていますか?

xlinkまた、XMLをXLink名前空間のプレフィックスとして使用するための見かけの設定と一致させるのではなく、コードに入れることができる回避策を見つけた人はいますか?

アップデート

私はいくつかの追加のテストを行いましたが、問題は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名前空間に「expected」プレフィックスを使用すると、問題なくシリアル化されます。

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

1 に答える 1

7

私はまだChromeにバグがあることを確信しています。これは、Barbarrosaが指摘したXLink属性XMLSerializerのSVG処理に対処しているときに発生した可能性があります。しかし、私が作成したバグレポートへの応答がなかったため、私たちは前進して問題を回避する必要がありました。

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名前空間に属性を付けた要素で属性が宣言されていることを確認するだけです。この関数はツリーをトラバースするため、非常に時間がかかる可能性があるため、Chromeバージョン22以降でのみ呼び出します。

ほとんどの場合xmlns:xlink、ドキュメント要素に名前空間を追加するだけで解決できることに注意してください。名前空間はそこから継承されるためです。しかし、私たちの場合、正規表現を使用してドキュメント要素を削除する他のコードがあったため、安全に再生し、必要な場所に属性を追加することにしました。

更新(20130324):

このバグはChromeCanary26で修正および検証されました。バージョンでも、自分で検証することができました25.0.1364.172 m

于 2012-11-13T15:40:24.637 に答える