2011年10月27日木曜日

JavaScript + XSLT の小技

ここ数年、一部界隈でアンチXMLみたいな動きがあったりするが、現実には XML はいろんな場面で使われている。中には数万行のものがあったりするけど、さすがにそのサイズになると、直接、内容を読もうとすると、結構不便だったりする。

というわけで、最近重宝している ブラウザと Javascript と XSLT を使った小技を書いてみる。

こんな感じの XML があるとする。

<?xml version="1.0"?>
<numerals>
  <numeral><arabic>1</arabic><jp>壱</jp><en>one</en></numeral>
  <numeral><arabic>2</arabic><jp>弐</jp><en>two</en></numeral>
  <numeral><arabic>3</arabic><jp>参</jp><en>thee</en></numeral>
</numerals>

これを XSLT で HTML に変換して、ブラウザ上で左下のようなリストを表示し、それぞれのリスト要素に設定されているハイパーリンクをクリックすると、右下の様に詳細が表示されるといった事をしたい。

数字2
日本語
英語two

以下、その方法。

====

リストを表示する XSLT は以下のようなものになる。ポイントは<a>要素を生成しているところで、javascript 関数 showDetail()に arabic 要素を渡すようなリンクが作られる。

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:template match="/">
    <ul>
      <xsl:for-each select="numerals/numeral">
        <li>
          <xsl:element name="a">
            <xsl:attribute name="href">
              javascript:showDetail(<xsl:value-of select="arabic"/>)
            </xsl:attribute>
            <xsl:value-of select="jp"/>
         </xsl:element>
        </li>
      </xsl:for-each>
    </ul>
  </xsl:template>
</xsl:stylesheet>

で、次に詳細を表示するためのXSLTは以下で、ポイントはパラメータ arabic をグローバルで宣言しているところ。

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:param name="arabic"/>
  <xsl:template match="/numerals/numeral">
    <xsl:for-each select=".[arabic=$arabic]">
      <table>
       <tr>
         <td>数字</td>
         <td><xsl:value-of select="arabic"/></td>
       </tr>
       <tr>
         <td>日本語</td>
         <td><xsl:value-of select="jp"/></td>
       </tr>
       <tr>
         <td>英語</td>
         <td><xsl:value-of select="en"/></td>
       </tr>
      </table>
    </xsl:for-each>
  </xsl:template>
</xsl:stylesheet>

いよいよ、Javascript と それを含むHTMLだけど、ソースは以下のようなものになる。

<html>
 <head>
  <script type="text/javascript" src="sarissa.js"></script>
  <script type="text/javascript">
   function loadXmlFile(fileName) {
     var result = Sarissa.getDomDocument();
     result.async = false;
     result.load(fileName);
     return result;
   }
   function replaceResultArea(xmlDom) {
     var serializer = new XMLSerializer(); 
     var output = serializer.serializeToString(xmlDom.documentElement);
 
     document.getElementById("resultArea").innerHTML = output;
   }
   function showList() {
     var xml = loadXmlFile("test.xml");
     var xslt = loadXmlFile("ul.xsl");

     var processor = new XSLTProcessor();
     processor.importStylesheet(xslt);
     var xmlDom = processor.transformToDocument(xml);

     replaceResultArea(xmlDom);
   }
   function showDetail(arabic) {
     var xml = loadXmlFile("test.xml");
     var xslt = loadXmlFile("detail.xsl");

     var processor = new XSLTProcessor();
     processor.importStylesheet(xslt);
     processor.setParameter("", "arabic", arabic);
     var xmlDom = processor.transformToDocument(xml);

     replaceResultArea(xmlDom);
   }
  </script>
 </head>
 <body onload="showList()"/>
   <div id="resultArea"/>   
 </body>
</html>

冒頭で参照している sarrisa.js はXMLを扱うための JavaScript ライブラリで http://dev.abiss.gr/sarissa/ からダウンロードできる。ただし Chrome がどうもサポートされてないっぽい。本当にそうなら残念(まあ、それほど困らないけど)。

以上、「(1)パラメータを与えつつ、(2)動的に XSLT を適用して、(3)ブラウザ上で表示を切り替える」方法。サンプルなんで、簡単なものだけどなんぼでも応用がきく。(例えば、静的ソース解析ツールが吐いたXML形式のレポートを分析したり、XMIで出力したUMLのドキュメントを解析してメトリクスを試算したりとか。)

ちなみに、個人的には XML それ自体に対する忌避感みたいなのは、全くといって良いほど無い。他の大抵の技術要素と同じく、上手く使えば役に立つし、下手に使えば役に立たないという単純な問題。

0 件のコメント:

コメントを投稿