綾小路龍之介の素人思考

[xhtml] Content-Type: application/xhtml+xml;の場合に失敗するjavascriptのdocument.write()メソッドはDOMでやっても失敗する。

結局問題は未定義の文字実体参照を使っていることが原因だったみたいなので、文字実体参照を適当な16進数表現か文字にしてしまう。

以下のxhtml文書をtest.htmlという名前で保存。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
    "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html version="-//W3C//DTD XHTML 1.1//EN"
      xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://www.w3.org/1999/xhtml
                          http://www.w3.org/MarkUp/SCHEMA/xhtml11.xsd"
>
  <head>
    <title>Virtual Library</title>
  </head>
  <body>
    <p>Moved to <a href="http://example.org/">example.org</a>.</p>
    <p>1 test string</p>
    <p>2 test string</p>
  </body>
</html>

以下の内容を.htaccessという名前でtest.htmlと同じディレクトリに保存。

AddType "application/xhtml+xml; charset=UTF-8" .html

設置したtest.htmlをサーバから取得。レスポンスヘッダは以下。htaccessの設定により、Content-Type: application/xhtml+xml;となっていることがわかる。

$ wget -S http://*************/test.html
--2011-11-06 11:16:24--  http://*************/test.html
Resolving *************... **************
Connecting to *************|**************|:80... connected.
HTTP request sent, awaiting response...
  HTTP/1.1 200 OK
  Date: Sun, 06 Nov 2011 02:16:30 GMT
  Server: Apache/2.2.3 (CentOS)
  Last-Modified: Sun, 06 Nov 2011 02:14:31 GMT
  ETag: "1a88d92-34d-7fa12fc0"
  Accept-Ranges: bytes
  Expires: Thu, 01 Jan 1970 00:00:00 GMT, -1
  Cache-Control: must-revalidate
  Pragma: no-cache
  Connection: close
  Content-Type: application/xhtml+xml; charset=utf-8
  Content-Language: ja
Length: unspecified [application/xhtml+xml]
Saving to: “test.html”

    [ <=>            ] 1,332       --.-K/s   in 0s

2011-11-06 11:16:29 (170 MB/s) - “test.html” saved [1332]

Firefox 7.0.1でtest.htmlをサーバから取得。Firebug 1.8.3でエラーを確認。エラーが無いことがわかる。

test.htmlを以下のように書き換え。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
    "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html version="-//W3C//DTD XHTML 1.1//EN"
      xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://www.w3.org/1999/xhtml
                          http://www.w3.org/MarkUp/SCHEMA/xhtml11.xsd"
>
  <head>
    <title>Virtual Library</title>
  </head>
  <body>
    <p>Moved to <a href="http://example.org/">example.org</a>.</p>
    <p>1 test string</p>
    <p>2 test string</p>
    <script type="application/ecmascript" src="/test.js"></script>
  </body>
</html>

以下のjavascriptのコードをtest.jsという名前でtest.htmlと同じディレクトリに保存。

document.write('<p>3 test string</p>');

Firefox 7.0.1でtest.htmlをサーバから取得。"2 test string"の後に"3 test string"と表示されることが期待されるが、そうならない。Firebug 1.8.3でエラーを確認。test.jsの1行目で"An attempt was made to use an object that is not, or is no longer, usable"というエラーが出ていることがわかる。これはContent-Type: application/xhtml+xml;の文書でdocument.write()が使えない問題。404 Blog Not Found:javascript - 決定版 - DOM時代のdocument.write()を参考にして以下のようにtest.htmlのheadにscriptタグを追加。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
    "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html version="-//W3C//DTD XHTML 1.1//EN"
      xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://www.w3.org/1999/xhtml
                          http://www.w3.org/MarkUp/SCHEMA/xhtml11.xsd"
>
  <head>
    <title>Virtual Library</title>
    <script type="application/ecmascript" src="/dom_document_write.js"></script>
  </head>
  <body>
    <p>Moved to <a href="http://example.org/">example.org</a>.</p>
    <p>1 test string</p>
    <p>2 test string</p>
    <script type="application/ecmascript" src="/test.js"></script>
  </body>
</html>

また、以下のjavascriptのコードをdom_document_write.jsという名前でtest.htmlと同じディレクトリに保存。

/*@cc_on @*/
/* if IE, do nothing (error 8004004, whatever that is) */
/*@if (@_jscript_version > 0)
@else @*/
document.getCurrentScript = function(){
  // fails when document.write nests like
  // document.write('<'+'script'+'>' +'document.write(...)' + '</'+'script'+'>')
  return (function (e) {
    if (!e) return null // gracefully report failure
    if (e.nodeName.toLowerCase() == 'script') return e;
      return arguments.callee(e.lastChild)
    })(document)
};

document.__write__ = document.write;

document.write = function (what, where) {
  if (!where) where = this.getCurrentScript();
  if (!where) return this.__write__(what);
  var here = where.previousSibling;
  if (!here || here.nodeType != 1 || here.className != '.written'){
    here = document.createElement('div');
    here.className =  '.written';
    where.parentNode.insertBefore(here, where);
  }
  if (what.nodeType){
    here.appendChild(what);
  }else{
    if (what.match(/^<script/i)){
      // needed to have your browser reevaluate the script
      this.__write__(what); 
    }
    else{
      here.innerHTML += what;
    }
  }
};
/*@end @*/

Firefox 7.0.1でtest.htmlをサーバから取得。"2 test string"の後に"3 test string"と表示される。Firebug 1.8.3でエラーを確認。エラーは無い。

test.jsを以下のように書き換え。

document.write('<p>3 test string</p>');
document.write('<p>4 test&nbsp;string</p>');

Firefox 7.0.1でtest.htmlをサーバから取得。"2 test string"の後に"3 test string"、その後に"4 test string"と表示されることが期待されるが、そうならない。Firebug 1.8.3でエラーを確認。"定義されていない実体が使用されています。"というエラー、test.jsの34行目(here.innerHTML += what;)で"An invalid or illegal string was specified"というエラーが出ていることがわかる。"3 test string"が成功したことを考慮すると、"4 test string"の代わりに"4 test string"とすればよいことは想像に難くない。問題はhtmlに直接&nbsp;を書いた場合はOKで、javascriptに&nbsp;があるとダメなのかということ。XMLのpredefined entitiesである&amp;、&lt;、&gt;、&quot;、&apos;は成功。また、&#x0160;等の数値実体参照は成功した。このことから、hereにxhtml1.1文書であることを示す適当プロパティが設定されていないことが問題と考えられる。

とりあえずの修正として、&nbsp;を" "に置換することにした。

l's gist: 1342587 — Gist

リファレンス

  1. application/xhtml+xml document write dom - Google 検索
  2. documentオブジェクト - JAVAスクリプト
  3. application/xhtml+xmlなページでは,document.write()は使えないそうな | 吟遊詩人の戯言
  4. M.C.P.C.: XHTMLをMIMEタイプapplication/xhtml+xmlにして、JavaScriptではまったことと解決法
  5. JACK THREE FIVE | articles
  6. 404 Blog Not Found:javascript - DOM時代のdocument.write()
  7. SCR21: DOM(ドキュメント・オブジェクト・モデル)を用いて、ページにコンテンツを追加する
  8. ちょっとしたメモ - 今どきのXHTMLメディアタイプ
  9. 404 Blog Not Found:javascript - 決定版 - DOM時代のdocument.write()
  10. DOM document.write - Google 検索
  11. l's gist: 1342587 — Gist
  12. XHTML Media Types - Second Edition
  13. Writing JavaScript for XHTML - MDN

ソーシャルブックマーク

  1. はてなブックマーク
  2. Google Bookmarks
  3. del.icio.us

ChangeLog

  1. Posted: 2010-03-10T04:26:13+09:00
  2. Modified: 2010-03-10T40:26:13+09:00
  3. Generated: 2017-05-11T23:09:19+09:00