XSLT 2.0で外部データを処理しXMLファイルを生成: xsl:for-each-groupによるグループ化

概要

XSLT 2.0ではunparsed-text()やcollection()関数の利用が可能となり、xsl:for-each-groupによるデータグループ化処理が実装されています。

処理フロー

  1. CSVファイルから従業員データを読み込み
  2. 個別XMLファイルを生成
  3. 複数XMLファイルを統合
  4. グループ化してソート出力

CSVデータフォーマット

氏名,役職,部署
Taro,Yamada,Engineer,Development
Hanako,Matsumoto,Manager,Sales

実装コード

個別ファイル生成XSLT

<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:func="http://example.com/functions" xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xsl:template name="main"> <xsl:variable name="source" select="func:get-source-path()"/> <xsl:variable name="text" select="unparsed-text($source)"/> <!-- 行単位処理 --> <xsl:for-each select="tokenize($text, '\n')[position() > 1]"> <xsl:call-template name="create-record"> <xsl:with-param name="data" select="."/> </xsl:call-template> </xsl:for-each> <!-- 統合ファイル作成 --> <xsl:call-template name="merge-files"> <xsl:with-param name="output" select="func:get-output-path()"/> </xsl:call-template> </xsl:template> <!-- 個別レコード作成 --> <xsl:template name="create-record"> <xsl:param name="data"/> <xsl:variable name="fields" select="tokenize($data, ',\s*')"/> <xsl:result-document href="employee-{position()}.xml"> <record> <first-name><xsl:value-of select="$fields[1]"/></first-name> <last-name><xsl:value-of select="$fields[2]"/></last-name> <title><xsl:value-of select="$fields[3]"/></title> <department><xsl:value-of select="func:clean-text($fields[4])"/></department> </record> </xsl:result-document> </xsl:template> <!-- ファイル統合 --> <xsl:template name="merge-files"> <xsl:param name="output"/> <xsl:result-document href="{$output}"> <all-records> <xsl:for-each select="collection('.?select=employee-*.xml')"> <xsl:copy-of select="."/> </xsl:for-each> </all-records> </xsl:result-document> </xsl:template> <!-- 空白除去関数 --> <xsl:function name="func:clean-text"> <xsl:param name="input"/> <xsl:value-of select="translate($input, ' ', '')"/> </xsl:function> <!-- パス取得関数 --> <xsl:function name="func:get-source-path"> <xsl:value-of select="'employees.csv'"/> </xsl:function> <xsl:function name="func:get-output-path"> <xsl:value-of select="'all_employees.xml'"/> </xsl:function> </xsl:stylesheet>

グループ化XSLT

<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:template name="main"> <xsl:variable name="data" select="doc('all_employees.xml')"/> <xsl:result-document href="grouped.xml"> <grouped-data> <xsl:for-each-group select="$data//record" group-by="department"> <xsl:sort select="current-grouping-key()"/> <group> <title><xsl:value-of select="current-grouping-key()"/></title> <xsl:for-each select="current-group()"> <xsl:sort select="first-name"/> <xsl:sort select="last-name"/> <item> <name> <xsl:value-of select="concat(first-name, ' ', last-name)"/> </name> <position><xsl:value-of select="title"/></position> </item> </xsl:for-each> </group> </xsl:for-each-group> </grouped-data> </xsl:result-document> </xsl:template> </xsl:stylesheet>

実行コマンド

java -jar saxon9he.jar -it:main -xsl:build.xslt
java -jar saxon9he.jar -it:main -xsl:group.xslt

出力結果

<grouped-data> <group> <title>Sales</title> <item> <name>Hanako Matsumoto</name> <position>Manager</position> </item> </group> <group> <title>Development</title> <item> <name>Taro Yamada</name> <position>Engineer</position> </item> </group> </grouped-data>

タグ: XSLT XSLT2.0 XML処理 データ変換 Saxon

8月1日 09:01 投稿