2009年6月21日

【Java】XML文書をXSLTで変換してみるサンプル【C#】

 DOM(Document Object Model)SAX(Simple API for XML)を使ったプログラムを書くのも良いけれど、XML文書の構造を変換するのならXLST(XSL Transformations)を利用した方が開発効率は遥かに高いです。 プログラミング言語の知識も必要ないですしね。(・∀・)ベンリ!!

入力するXMLファイル

 それでは試しに先日DOMとSAXで作ったプログラムと同じ結果を出力するXSLTスタイルシートを書いてみましょう。 ソースXML文書はGundamList.xmlを使います。
<?xml version="1.0" encoding="Shift_JIS" ?>

<!DOCTYPE gundamList SYSTEM "GundamList.dtd">

<gundamList xmlns="urn:gundam:anime">
<gundam media="TV">
<name>機動戦士ガンダム</name>
<calendar jpn="宇宙世紀" eng="U.C.">0079</calendar>
<director>富野由悠季</director>
</gundam>
<gundam media="TV">
<name>機動戦士Zガンダム</name>
<calendar jpn="宇宙世紀" eng="U.C.">0087</calendar>
<director>富野由悠季</director>
</gundam>
<gundam media="TV">
<name>機動戦士ガンダムZZ</name>
<calendar jpn="宇宙世紀" eng="U.C.">0088</calendar>
<director>富野由悠季</director>
</gundam>
<gundam media="MOVIE">
<name>機動戦士ガンダム 逆襲のシャア</name>
<calendar jpn="宇宙世紀" eng="U.C.">0093</calendar>
<director>富野由悠季</director>
</gundam>
<gundam media="OVA">
<name>機動戦士ガンダム0080 ポケットの中の戦争</name>
<calendar jpn="宇宙世紀" eng="U.C.">0080</calendar>
<director>高山文彦</director>
</gundam>
<gundam media="MOVIE">
<name>機動戦士ガンダムF91</name>
<calendar jpn="宇宙世紀" eng="U.C.">0123</calendar>
<director>富野由悠季</director>
</gundam>
<gundam media="OVA">
<name>機動戦士ガンダム0083 STARDUST MEMORY</name>
<calendar jpn="宇宙世紀" eng="U.C.">0083</calendar>
<director>加瀬充子</director>
<director>今西隆志</director>
</gundam>
<gundam media="TV">
<name>機動戦士Vガンダム</name>
<calendar jpn="宇宙世紀" eng="U.C.">0153</calendar>
<director>富野由悠季</director>
</gundam>
<gundam media="TV">
<name>機動武闘伝Gガンダム</name>
<calendar jpn="未来世紀" eng="F.C.">60</calendar>
<director>今川泰宏</director>
</gundam>
<gundam media="TV">
<name>新機動戦記ガンダムW</name>
<calendar jpn="アフターコロニー" eng="A.C.">195</calendar>
<director>池田成</director>
<director>高松信司</director>
</gundam>
<gundam media="TV">
<name>新機動戦記ガンダムX</name>
<calendar jpn="アフターウォー" eng="A.W.">15</calendar>
<director>高松信司</director>
</gundam>
<gundam media="OVA">
<name>機動戦士ガンダム 第08MS小隊</name>
<calendar jpn="宇宙世紀" eng="U.C.">0079</calendar>
<director>神田武幸</director>
<director>飯田馬之介</director>
</gundam>
<gundam media="OVA">
<name>新機動戦記ガンダムW Endless Waltz</name>
<calendar jpn="アフターコロニー" eng="A.C.">196</calendar>
<director>青木康直</director>
</gundam>
<gundam media="OVA">
<name>機動戦士ガンダム 第08MS小隊 特別編 ラスト・リゾート</name>
<calendar jpn="宇宙世紀" eng="U.C.">0079</calendar>
<director>森邦宏</director>
<director>仕舞屋鉄</director>
</gundam>
<gundam media="TV">
<name>∀ガンダム</name>
<calendar jpn="正暦" eng="C.C.">2345</calendar>
<director>富野由悠季</director>
</gundam>
<gundam media="TV">
<name>機動戦士ガンダムSEED</name>
<calendar jpn="コズミック・イラ" eng="C.E.">71</calendar>
<director>福田己津央</director>
</gundam>
<gundam media="TV">
<name>機動戦士ガンダムSEED DESTINY</name>
<calendar jpn="コズミック・イラ" eng="C.E.">73</calendar>
<director>福田己津央</director>
</gundam>
<gundam media="OVA">
<name>機動戦士ガンダムSEED C.E.73 STARGAZER</name>
<calendar jpn="コズミック・イラ" eng="C.E.">73</calendar>
<director>西澤晋</director>
</gundam>
<gundam media="TV">
<name>機動戦士ガンダム00 ファーストシーズン</name>
<calendar jpn="西暦" eng="A.D.">2307</calendar>
<director>水島精二</director>
</gundam>
<gundam media="TV">
<name>機動戦士ガンダム00 セカンドシーズン</name>
<calendar jpn="西暦" eng="A.D.">2312</calendar>
<director>水島精二</director>
</gundam>
</gundamList>


XSLTスタイルシートの課題1

 まずは「GundamList.xmlの中から富野由悠季監督のガンダム作品を抽出する」XSLTスタイルシートで、次のような出力結果を目指します。
U.C.0079 機動戦士ガンダム
U.C.0087 機動戦士Zガンダム
U.C.0088 機動戦士ガンダムZZ
U.C.0093 機動戦士ガンダム 逆襲のシャア
U.C.0123 機動戦士ガンダムF91
U.C.0153 機動戦士Vガンダム
C.C.2345 ∀ガンダム
以上、7作品


 色々な書き方で実現できるのですけど、今回はXMLマスター:プロフェッショナル試験に出題されるkey関数を使用してみます。

XSLTスタイルシート(GundamSax.xsl)は次のようになりました。 文字列比較だらけになってしまうJavaやC#のコードよりスッキリしてますよね。
<?xml version="1.0" encoding="Shift_JIS" ?>

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ani="urn:gundam:anime">

<xsl:key name="director" match="ani:gundamList/ani:gundam" use="ani:director" />
<xsl:variable name="kantoku" select="'富野由悠季'" />

<xsl:output method="text" />
<xsl:template match="/">
<xsl:apply-templates select="key('director', $kantoku)" />

<xsl:text>以上、</xsl:text>
<xsl:value-of select="count(key('director', $kantoku))" />
<xsl:text>作品</xsl:text>
</xsl:template>

<xsl:template match="ani:gundam">
<xsl:value-of select="ani:calendar/@eng" />
<xsl:value-of select="ani:calendar" />
<xsl:text> </xsl:text>
<xsl:value-of select="ani:name" />
<xsl:text>&#xA;</xsl:text>
</xsl:template>

</xsl:stylesheet>



XSLTスタイルシートの課題2

 続いて「GundamList.xmlの中から宇宙世紀(U.C.)のガンダムシリーズを抜き出して、作中の年表順にソートする」XSLTスタイルシートで、次のような出力結果を目指します。
U.C.0079 機動戦士ガンダム
U.C.0079 機動戦士ガンダム 第08MS小隊
U.C.0079 機動戦士ガンダム 第08MS小隊 特別編 ラスト・リゾート
U.C.0080 機動戦士ガンダム0080 ポケットの中の戦争
U.C.0083 機動戦士ガンダム0083 STARDUST MEMORY
U.C.0087 機動戦士Zガンダム
U.C.0088 機動戦士ガンダムZZ
U.C.0093 機動戦士ガンダム 逆襲のシャア
U.C.0123 機動戦士ガンダムF91
U.C.0153 機動戦士Vガンダム
以上、10作品


 これはkey関数で抽出した結果にxsl:sortを適用するだけですね。

XSLTスタイルシート(GundamDom.xsl)は次のようになりました。 ソート処理が組み込まれていると楽チンなことこの上ない。
<?xml version="1.0" encoding="Shift_JIS" ?>

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ani="urn:gundam:anime">

<xsl:key name="century" match="ani:gundamList/ani:gundam" use="ani:calendar/@eng" />
<xsl:variable name="eng" select="'U.C.'" />

<xsl:output method="text" />
<xsl:template match="/">
<xsl:apply-templates select="key('century', $eng)">
<xsl:sort select="ani:calendar" data-type="number" />
</xsl:apply-templates>

<xsl:text>以上、</xsl:text>
<xsl:value-of select="count(key('century', $eng))" />
<xsl:text>作品</xsl:text>
</xsl:template>

<xsl:template match="ani:gundam">
<xsl:value-of select="ani:calendar/@eng" />
<xsl:value-of select="ani:calendar" />
<xsl:text> </xsl:text>
<xsl:value-of select="ani:name" />
<xsl:text>&#xA;</xsl:text>
</xsl:template>

</xsl:stylesheet>



JavaでXSLTスタイルシートを処理する

 XSLTスタイルシートが用意できたらXLSTプロセッサに処理してもらいます。 JavaとC#にはXSLTを処理するクラスが用意されてるので使ってみましょう。

 Javaのコード(GundamXslt.java)は次のようになります。
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.stream.StreamSource;
import javax.xml.transform.stream.StreamResult;

public class GundamXslt
{
public static void main(String[] args)
{
try
{
// XSLファイルを読み込む
StreamSource tplXsl = new StreamSource("GundamDom.xsl");
TransformerFactory trf = TransformerFactory.newInstance();
Transformer xslt = trf.newTransformer(tplXsl);

// XMLファイルをXSLTで変換して出力
StreamSource srcXml = new StreamSource("GundamList.xml");
xslt.setOutputProperty("encoding", "Shift_JIS");
xslt.transform(srcXml, new StreamResult(System.out));
}
catch(Exception ex)
{
ex.printStackTrace();
}
}
}


C#でXSLTスタイルシートを処理する

 C#のコード(GundamXslt.cs)は次のようになります。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Xsl;
using System.Xml.XPath;

namespace GundamXslt
{
class GundamXslt
{
static void Main(string[] args)
{
// XSLファイルを読み込む
XslCompiledTransform xslt = new XslCompiledTransform();
xslt.Load(@"..\..\GundamSax.xsl");

// XMLファイルをXSLTで変換して出力
XPathDocument doc = new XPathDocument(@"..\..\GundamList.xml");
XsltArgumentList argList = new XsltArgumentList();
xslt.Transform(doc, argList, Console.Out);
}
}
}


 とりあえずXLSTで実装しておいて、もし速度が必要なら後でDOMやSAXで書き直す開発スタイルが良さそうですね。( ゚Д゚)y─┛~~

 

 XSLTはXMLマスターのベーシックとプロフェッショナル両方の試験範囲です。 これら2冊分の知識で大抵のことはできそうですけど、本格的にXSLTを使うならハンドブックが欲しいなぁ。 でも新しめのXSLT書籍は無さそうね。

【関連記事】

0 件のコメント:

コメントを投稿