ubichupas.net

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

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

入力するXMLファイル

それでは試しに先日DOMとSAXで作ったプログラムと同じ結果を出力するXSLTスタイルシートを書いてみましょう。 ソースXML文書はGundamList.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スタイルシートで、次のような出力結果を目指します。

cmd.exe
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マスター:プロフェッショナル試験に出題されるxsl:key関数を使用してみます。 XSLTスタイルシート(GundamSax.xsl)は次のようになりました。 文字列比較だらけになってしまうJavaやC#のコードよりスッキリしてますよね。

GundamSax.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="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>
</xsl:text>
    </xsl:template>
    
</xsl:stylesheet>

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

続いて「GundamList.xmlの中から宇宙世紀(U.C.)のガンダムシリーズを抜き出して、作中の年表順にソートする」XSLTスタイルシートで、次のような出力結果を目指します。

cmd.exe
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作品

これはxsl:key関数で抽出した結果にxsl:sortを適用するだけでできます。 XSLTスタイルシート(GundamDom.xsl)は次のようになりました。 ソート処理が組み込まれていると楽チンなことこの上ない。

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>
</xsl:text>
    </xsl:template>
    
</xsl:stylesheet>

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

XSLTスタイルシートが用意できたらXLSTプロセッサに処理してもらいます。 JavaとC#にはXSLTを処理するクラスが用意されてるので使ってみましょう。 Javaのコード(GundamXslt.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)は次のようになります。

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─┛~~

0 件のコメント: