2013年1月8日火曜日

xslでブラウザ判定をしてsvgの描画内容を変更する

webブラウザは以前よりも標準化されてきたとは言え,まだまだ細かい部分で動作が安定しておらず,ブラウザ毎のコードを必要とする場合もあります.その際に必要となるブラウザ判定処理は意外に面倒で,これといった決定版が無いといった問題があります.

今回紹介するxslを使ったブラウザ判定はこの解決策とは成り得ないものの,知っているとちょっと便利かもしれません.

xslとは


xslはxml文書に対するスタイルシートの一つで,一般的なcssと同様に文書に対する見た目を制御する役割を持っています.ですが,cssよりも強力な仕組みを備えており,xml文書の構造そのものを変更することができます.つまり,元の文書はそのままに,見た目を(x)htmlやsvgの他にもプレーンテキストやcsv等に変換することができるのです.

その役割上xslを直接htmlに適用することはできませんが,元々xmlをベースとしているsvgであればいろいろ面白いことができそうです.

system-property関数を使ってみる


さて,このxslの仕様を眺めていて気がついたこととして,system-property関数というものがあるようです.この関数はxslを動作させているxmlプロセッサの情報を返すもので,次のようなコードを記述することで内容を確認することができます.

  • xslの内容
<?xml version="1.0" standalone="no"?>
<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:svg="http://www.w3.org/2000/svg">
 <xsl:output
  method="xml"
  encoding="utf-8"
  doctype-public="-//W3C//DTD SVG 1.1//EN"
  doctype-system="http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"/>
 <xsl:template match="svg:svg">
  <xsl:copy>
   <xsl:copy-of select="@*"/>
   <svg:g fill="black">
    <svg:text y="20">
     Version:
     <xsl:value-of select="system-property('xsl:version')" />
    </svg:text>
    <svg:text y="40">
     Vendor:
     <xsl:value-of select="system-property('xsl:vendor')" />
    </svg:text>
    <svg:text y="60">
     Vendor URL:
     <xsl:value-of select="system-property('xsl:vendor-url')" />
    </svg:text>
   </svg:g>
  </xsl:copy>
 </xsl:template>
</xsl:stylesheet>
  • svgの内容
<?xml version="1.0" standalone="no"?>
<?xml-stylesheet href="switch.xsl" type="application/xml"?>
<svg width="400px" height="200px" viewBox="0 0 400 200" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1">
 <desc></desc>
</svg>

これを実際に試してみると次のような値が返って来ました.
versionvendorvendor-url
firefox1Transformiixhttp://www.mozilla.org/projects/xslt/
chrome1.0libxslthttp://xmlsoft.org/XSLT/
safari
opera1.0Operahttp://www.opera.com/
ie1Microsofthttp://www.microsoft.com

概ねレンダリングエンジン毎に異なる結果が得られるようです.つまり,この値を応用すればsvgの描画内容を切り替えられることになります.

system-property関数を使って描画内容を切り替える


では早速試してみましょう.方針としてはブラウザ毎に表示を切り替えたい図形にclass属性を設定し,style要素で非表示としておき,その内容をxslで生成したstyle要素で打ち消すようにします.ブラウザ毎に非表示の取り消し対象を切り替える訳です.
  • svgの内容
<?xml version="1.0" standalone="no"?>
<?xml-stylesheet href="switch.xsl" type="application/xml"?>
<svg width="400px" height="200px" viewBox="0 0 400 200" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1">
 <style id="hide">
  .firefox,.chrome,.opera,.ie{display:none;}
 </style>
 <g fill="black" transform="translate(0,20)">
  <text>このブラウザは「<tspan class="firefox">firefox</tspan><tspan class="chrome">chrome</tspan><tspan class="opera">opera</tspan><tspan class="ie">ie</tspan>」です.</text>
 </g>
 <circle cx="100" cy="100" r="60" class="firefox" fill="red"/>
 <circle cx="150" cy="100" r="60" class="chrome" fill="blue"/>
 <circle cx="200" cy="100" r="60" class="opera" fill="green"/>
 <circle cx="250" cy="100" r="60" class="ie" fill="orange"/>
</svg>
  • xslの内容
<?xml version="1.0" standalone="no"?>
<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:svg="http://www.w3.org/2000/svg">
 <!--各ノードをコピーする-->
 <xsl:template match="*">
  <xsl:copy>
   <xsl:copy-of select="@*"/>
   <xsl:apply-templates/>
  </xsl:copy>
 </xsl:template>
 <!--ブラウザごとのスタイルを挿入する-->
 <xsl:template match="svg:style[@id='hide']">
  <xsl:copy>
   <xsl:apply-templates/>
  </xsl:copy>
  <style xmlns="http://www.w3.org/2000/svg">
   <xsl:choose>
    <xsl:when test="system-property('xsl:vendor')='Transformiix'">.firefox{display:inline}</xsl:when>
    <xsl:when test="system-property('xsl:vendor')='libxslt'">.chrome{display:inline}</xsl:when>
    <xsl:when test="system-property('xsl:vendor')='Opera'">.opera{display:inline}</xsl:when>
    <xsl:when test="system-property('xsl:vendor')='Microsoft'">.ie{display:inline}</xsl:when>
   </xsl:choose>
  </style>
 </xsl:template>
</xsl:stylesheet>
それでは実際に表示してみましょう.


このようにスクリプトなしに内容を切り替えることに成功しました.なおここではcssとxslとを切り替えていますが,xsl単体で切り替えを実現することもできます.この部分は実装に依存するため,深追いはしないこととします.

まとめ


ブラウザ判定には様々な方法がありましたが,svgにおいては以前紹介したfeature文字列によるブラウザ判定がありました.しかしこの方法はsvgの実装状況が変化するにつれ内容が変更となる可能性を否定できません.

その一方でxslのsystem-property関数による方法はブラウザの値を直接参照するため,ブラウザ識別の確実性が高いというメリットがあります.またxmlをベースとしているため,htmlにおけるインラインsvgでは利用できないなど汎用性に欠けるものの,javascriptすら必要ないという点は覚えていて損はないと思われます.

0 件のコメント:

コメントを投稿