2008-07-16 (Wed)
Adobe Flash をクロスブラウザで埋め込み表示させる Valid な XHTML 1.0/1.1
目的・経緯
embed 要素は XHTML 1.0/1.1 では定義されておらず、画像以外のオブジェクト埋め込みには object 要素だけで行います。しかし object 要素は以前からブラウザごとの実装に差異が多く、使いどころが難しくて結局 DTD を HTML 4.01 にして embed タグを書かざるを得ないということがままありました。
ここでは、それを解決するために色々書き方を変えては異なる環境でテストし、メジャーな環境すべてで表示され、且つ Valid な (正当な) XHTML になる記述を模索してみました。
表示されることを確認したブラウザ
- Opera 9.51 (Build 10081)
- Firefox 3.0 (Mozilla/5.0 (Windows; U; Windows NT 5.1; ja; rv:1.9) Gecko/2008052906 Firefox/3.0)
- Safari 3.1.2 (5525.20.1)
- Internet Explorer 7 (7.0.5730.11)
- Internet Explorer 6 (6.0.2900.2180.xpsp_sp2_gdr.070227-2254)
他の環境での結果報告もいただけると嬉しいです。
- thanks to d:id:tomoya for Safari 3.1.2
成功例
最小構成
<object data="http://example.com/something.swf" type="application/x-shockwave-flash" width="400" height="300"> <param name="movie" value="http://example.com/something.swf" /> </object>
CSS 使用(推奨?)
width と height の指定はそれぞれ以下のように CSS で代用することもできます。(どちらであるべきかはまた別のお話)
object#some-movie { width: 400px; /* 単位指定しないと Opera 9.51 で駄目 */ height: 300px; }
<object data="http://example.com/something.swf" type="application/x-shockwave-flash" id="some-movie"> <param name="movie" value="http://example.com/something.swf" /> </object>
代替内容あり(推奨)
今回調査した環境以外への対策として、例えば以下のように代替内容も用意しておきましょう。
<object data="http://example.com/something.swf" type="application/x-shockwave-flash" width="400" height="300"> <param name="movie" value="http://example.com/something.swf" /> <a href="http://example.com/something.swf">Some Movie</a> </object>
失敗例
失敗例 (movie 変数指定なし)
name="movie" のパラメタ指定がないと IE 6 と IE 7 で読み込みが終了しませんでした。神崎さん曰く、ActiveX が原因の様。
<object data="http://example.com/something.swf" type="application/x-shockwave-flash" width="400" height="300"> </object>
失敗例 (data 属性なし)
param で指定したことで冗長になったことで data 属性を試しに削ってみたところ、Firefox 3、IE 7、IE 6 で表示されませんでした。(それはそれで正しい動作という気もしますが)
<object type="application/x-shockwave-flash" width="400" height="300"> <param name="movie" value="http://example.com/something.swf" /> </object>
失敗例 (width と height の指定なし)
HTML や CSS による width・height 幅の指定がないと Opera 9.51、Firefox 3、Safari 3.1.2、IE 7、IE 6 で表示がおかしくなりました。img 要素のようにはいかないのですね。
<object data="http://example.com/something.swf" type="application/x-shockwave-flash" > <param name="movie" value="http://example.com/something.swf" /> </object>
失敗例 (classid 属性あり)
以下のように classid 属性を指定すると Firefox 3 で表示されませんでした。
<object data="http://example.com/something.swf" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" type="application/x-shockwave-flash" width="400" height="300"> <param name="movie" value="http://example.com/something.swf" /> </object>
これには嵌まりました。有効活用されるべき HTML 記述を削るのではなく、問題となるブラウザデフォルトの CSS ルールを消して対処すべきかもしれません。ただ今回は HTML コード主体の話なので、任意属性ということもあり、最小構成からは削りました。
失敗例 (type 属性なし)
classid と type どちらの属性も無いと、IE 7、IE 6 で Windows Media Player らしき UI が埋め込まれ、ActiveX 許可の確認ポップアップが出て、しかし OK しても再生されないという状態に。
<object data="http://example.com/something.swf" width="400" height="300"> <param name="movie" value="http://example.com/something.swf" /> </object>
総評・雑感
ゆの in XSLT 2.0
コード
<?xml version="1.0" encoding="utf-8"?> <!--バージョン宣言と「xs」および「ひだまり」の名前空間宣言--> <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:ひだまり="http://d.hatena.ne.jp/keyword/%A4%E6%A4%CE%20in%20language"> <!--独自要素 *1--> <ひだまり:スケッチ version="×365"> X / _ / X < 来週も見てくださいね! </ひだまり:スケッチ> <!--グローバル変数(引数)--> <xsl:param name="ひだまり:filepath" select="'file:/C://hoge/x365.txt'" as="xs:string"/> <!--エントリポイント--> <xsl:template match="/"> <!--最終出力--> <xsl:result-document href="{$ひだまり:filepath}"> <xsl:value-of select="ひだまり:unYunoize(document('')/*/ひだまり:スケッチ[position() = 1])"/> </xsl:result-document> </xsl:template> <!--独自関数--> <xsl:function name="ひだまり:unYunoize" as="xs:string"> <!--引数--> <xsl:param name="yuno" as="element()"/> <!--内容--> <xsl:variable name="result"> <xsl:analyze-string select="$yuno/child::text()" regex="(.*)<(.*)"> <xsl:matching-substring> <!--マッチした regex-group(1) の値 'X / _ / X ' を取得し、 tokenize 関数により xs:string+ 型のノード集合 ('X', '/', '_', '/', 'X') にし、 for-each ループにかける。--> <!--(この辺りのプロセスに特に意味はない。無理やり紹介したかっただけ。)--> <xsl:for-each select="tokenize(regex-group(1), ' ')"> <xsl:value-of select=" if (position() = 3) then replace(name($yuno), ':', '') else ''"/> </xsl:for-each> <xsl:value-of select="$yuno/@version"/> <xsl:value-of select="regex-group(2)"/> </xsl:matching-substring> </xsl:analyze-string> </xsl:variable> <!--返り値--> <xsl:sequence select="$result"/> </xsl:function> </xsl:stylesheet>
処理前
このスタイルシートをデフォルトスタイルシートを適用させないブラウザ (例えば Opera) で開くと「1」のテキストノードだけが実体参照も展開され表示されます:
X / _ / X < 来週も見てくださいね!
要素名とするのも XPath 式とするのも先にやられたので苦肉の策として、ね。。いや、でもこれは実に「XML らしい」と思うんだ!
処理後
処理系に Saxon を使うなら、以下のようなコマンドを実行します:
java -jar saxon -s:yuno-in-xslt20.xsl -xsl:yuno-in-xslt20.xsl
結果 ('file:/C://hoge/x365.txt'):
ひだまりスケッチ×365 来週も見てくださいね![EOF]
ポイント
- XML らしく(コード中にそのままリテラルを書けるのは多くの他言語にない)
- XSLT の自称中級者的な使い方
- XSLT 2.0 らしく(1.0 じゃないからこそできることを紹介しておいた)
- xsl:result-document 要素の追加により最終出力の多様化・明確化が可能に。
- xsl:function 要素の追加により独自関数の定義が可能に。
- ただただ素晴らしい。
- as 属性による型付けで返り値の明確化が可能に。xs:QName* や element()? などとすれば個数を指定できる。
- xsl:analyze-string 要素および regex 系の XPath 2.0 関数により文字列処理能力が飛躍的に向上。
- fn:translate(笑)
- XPath 式内での条件分岐 (if-then-else)
- キモイけど便利
- xsl:sequence 要素によりシーケンスコンストラクタ返り値の明確化が可能に。
- コードが読み易くなった。
- XSLT 1.0 における「結果ツリーフラグメント (Result Tree Fragment)」すらも別の内容生成にかけられるようになった。
- 激しく融通が利くようになった。
素晴らしい。
盲点だったけど確かにこれなら従来比でコードも短く済んでかつW3C(XHTML)遵守できますわな。