XSLTとXPathの関数の理解
XSLTとXPathの関数を使わずにXML文書を変換することは、よほど簡単な変換でない限り難しいものとなります。すべて紹介したいところですが、当記事ではMeigara.xmlからshop.xmlを変換するXSLTスタイルシートの説明中に個別に紹介します。XSLTとXPathの関数についてはXSL Transformations (XSLT) Version 1.0およびXML Path Language (XPath) Version 1.0を参考にしていただければと思います。
XML文書からXML文書への変換
ツリーとノード、ロケーションパス、関数が理解できればXSLTスタイルシートを記述する準備は整ったと言えます。さっそく、冒頭で紹介したMeigara.xmlからshop.xmlへ変換するXSLTスタイルシートを記述します。リスト3がそのスタイルシートであるXSLTSample02.xslです。
001:<?xml version="1.0" encoding="UTF-8"?>
002:<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
003: <xsl:output method="xml" indent="yes"/>
004:
005: <xsl:template match="/MEIGARAS">
006: <xsl:element name="SHOP">
007: <xsl:element name="GREETING">
008: <xsl:attribute name="OWNER"><xsl:text>tomoharu</xsl:text></xsl:attribute>
009: <xsl:text>店主の好みの芋焼酎を厳選しました。</xsl:text>
010: </xsl:element>
011: <xsl:element name="{local-name(self::node())}">
012: <xsl:apply-templates/>
013: </xsl:element>
014: </xsl:element>
015: </xsl:template>
016:
017: <xsl:template match="MEIGARA">
018: <xsl:element name="{local-name(self::node())}">
019: <xsl:apply-templates select="child::NAME"/>
020: <xsl:apply-templates select="child::ABV"/>
021: <xsl:apply-templates select="child::VOLUME"/>
022: <xsl:apply-templates select="child::PRICE"/>
023: <xsl:element name="MANUFACTURER"/>
024: </xsl:element>
025: </xsl:template>
026:
027: <xsl:template match="NAME">
028: <xsl:element name="{local-name(self::node())}">
029: <xsl:attribute name="KANA"/>
030: <xsl:value-of select="self::node()"/>
031: </xsl:element>
032: </xsl:template>
033:
034: <xsl:template match="ABV">
035: <xsl:element name="{local-name(self::node())}">
036: <xsl:attribute name="UNIT"><xsl:text>%</xsl:text></xsl:attribute>
037: <xsl:value-of select="self::node()"/>
038: </xsl:element>
039: </xsl:template>
040:
041: <xsl:template match="VOLUME">
042: <xsl:element name="{local-name(self::node())}">
043: <xsl:attribute name="UNIT"><xsl:text>ml</xsl:text></xsl:attribute>
044: <xsl:value-of select="self::node()"/>
045: </xsl:element>
046: </xsl:template>
047:
048: <xsl:template match="PRICE">
049: <xsl:element name="{local-name(self::node())}">
050: <xsl:attribute name="UNIT"/>
051: <xsl:value-of select="self::node()"/>
052: </xsl:element>
053: </xsl:template>
054:
055:</xsl:stylesheet>
Meigara.xmlからshop.xmlに変換するには、新しい要素の作成と新しい属性の作成の方法を習得するだけです。新しい要素を作るにはxsl:element、新しい属性を作るにはxsl:attribute要素を使用します。
- 6行目でSHOP要素を作成し、7行目から10行目でGREETING要素とそのOWNER要素を作成しています。7行目から10行目から分かるとおり、xsl:element要素の中でxsl:attribute要素を使用すると、要素とそれに関連する属性を一度に作成できます。また、固定した属性値や要素のテキストを挿入したい場合、xsl:textを使用します。8行目でOWNER属性の値を、9行目でGREETING要素のテキストを挿入しています。
- 11行目から13行目も要素を作成していますが、入力ツリーの要素名と同じ名称にしたい場合、{local-name(self::node())}のようにname属性を設定します。難しそうに見えますが、local-name()関数はコンテキストノードからノード名を取り出します。引数のself::node()はステップで説明したように軸としてselfを、ノードテキストとしてnode()関数を使っています。実はself::node()は"."という1文字で表すことができます。従ってlocal-name(.)でも構いません。意味としては自分自身のノード名である「MEIGARAS」を取りだしていることになります。当記事では省略形は紹介しませんが、仕様書で確認してください。12行目のxsl:apply-templatesをxsl:element要素を挟むことで、その子孫要素をMEIGARAS要素に挿入できます。
- 17行目から25行目でMEIGARA要素を作成しています。19行目から22行目でNAME要素、ABV要素、VOLUME要素、PRICE要素を作成するためのテンプレートを呼び出しています。23行目でMANUFACTURER要素を作成しています。
- 27行目から32行目はNAME要素とKANA属性を作成しています。34行目から39行目でABV要素とUNIT属性を作成しています。41行目から46行目でVOLUME要素とUNIT属性を作成しています。48行目から53行目でPRICE要素とUNIT属性を作成しています。ABV属性の場合は「%」、VOLUME属性の場合、「ml」で固定しているためxsl:textで属性値を設定しています。
