XSLファイルを使って、SpringMVCでCSV出力をおこなう方法

SpringFrameWork

WEBアプリケーションにおいて、サーバでCSVを作成して、クライアント(ブラウザ)にダウンロードする、といった要件は頻繁に発生します。


SpringMVCでXSLファイルを上手に使えば、簡単にCSVファイルの作成とダウンロードの機能を作成することができます。


今回は、SpringMVCでCSV出力をおこなう方法を紹介します。
Javaで自力でゴリゴリ作成する方法ではなく、XSLファイルを使ってCSV出力おこなう方法となります。


XSLファイルとは、XMLファイルのスタイルを定義しているファイルになります。
出力するCSVファイルのレイアウトをXSLファイルに定義してあらかじめサーバ上に格納しておき、CSVファイルを出力する際に使用します。


XSLファイルとは何か?


XSL(eXtensible Style Language)ファイルは、XML 文書を他の文書タイプに変換したり、出力をフォーマットする際に使用できるスタイルシートです。
Styleという言葉が使われていることからもわかるように、XMLのスタイルシートがXSLになります。


このXSLファイルで便利なのが、テンプレート関数というちょっとしたロジックをXSLファイル内で使用することができる点です。
例えば、以下のような関数です。


  • テンプレート関数の定義の仕方(xsl:template、xsl:param)
  • 引数の値の参照の仕方($引数名)
  • 条件分けの仕方(xsl:if、xsl:choose)
  • XSLT関数(not、contains、substring-before、substring-after)
  • XSLT関数の使い方(<xsl:value-of select=”XSLT関数 (引数…)” />)
  • 定義されたテンプレート関数の呼び出し方(xsl:call-template、xsl:with-param:再帰呼び出しの箇所)

上記のような関数もあらかじめXSLファイル内に定義することができます。


以下に、よく使う関数を紹介していきます。


文字列の連結


concat(str1,str2,str3,・・・)
str1、str2、str3、を連結


文字列の調査


contains(str, substr)
strの中のsubstrを検索。
存在する場合はtrueを通知


数字のフォーマッティング


format-number(number, format)
format-number(number, format, formatType)
numberの数字を、formatで指定されたフォーマットに変換して出力します。


空白の除去


normalize-space(str)
strから空白を除外した文字列を返却します


先頭文字のチェック


starts-with(str, substr)
strがsubstrで始まっているかをチェックします。
始まっている場合はtrueを通知。


文字列への変換


string(val)
valを文字列に変換します。


文字列の長さを取得


string-length(str)
strの長友を取得します。


文字列の抜き出し


substring(str, start)
substring(str, start, length)
strに対して、start位置からlengthの長さの文字列を取得します。


文字列の抜き出し(前文字列の取得)


substring-before(str, substr)
strからsubstrの文字列を検索し、見つかったらその前の文字列を取得します。


substring-after(後文字列の取得)


substring-after(str, substr)
strからsubstrの文字列を検索し、見つかったらその後の文字列を取得します。


文字列の置換


translate(str, src, dest)
strに含まれるsrcという文字列をdestに変換します。


切り上げ


ceiling(val)
valの切り上げをおこないます。


ノード数の取得


count(node)
XML内に含まれるnodeで指定されたノードの数を取得します。

<a>
  <b></b>
  <b></b>
</a>

この例で、’b’のノード数は2です。


切り下げ


floor(val)
valの切り下げをおこないます。


数値に変換


number(any)
anyを数値に変換します。


四捨五入


round(val)
valを四捨五入します。


加算


sum(node)
nodeで指定されている値を加算し、数値で返却します。


<a>
    <b>10</b>
    <b>10</b>
</a>

sum(‘b’)の返却値は20です。


現在のノード取得


current()
現在位置のノードを取得します。


現在のノードの最下層ノードを取得


last()


nodeのローカル名(名前空間を外したもの)を取得


local-name(node)


現在のノード名を取得


name()


現在のノードの名前空間URIを取得


namespace-uri()


現在のノード位置を数値で取得


position()


boolean型への変換


boolean(any)
anyをboolean(true or false)に変換します。


falseの出力


false()
boolean型のfalseを出力します。


trueの出力


true()
boolean型のtrueを出力します。


否定


not(boolean)
booleanの否定値をbooleanで出力します。


ドキュメントルートの取得


document(uri)
uriのドキュメントルートを出力します。


xsltで解釈できるxlstノードかを判定


element-available(str)
返り値はbooleanです。


xsltで解釈できる関数かを判定


function-available(func)


ノードに固有の値を割り当て


generate-id(node)


該当するidのノードを取得


id(any)


キー値を返却


key(str any)
str内のハッシュに、anyで指定される表現を返却します。


XSLT固有値の取得


system-property(str)
str内のXSLT固有の値を取得します。


<!entity>タグ値を取得


unparsed-entity-uri()
<!entity>タグで指定されている値を取得します。


CSV出力のサンプルソース


CSV出力のサンプルソースを紹介します。


SpringMVCのコントローラクラスに実装することを想定しています。


@RequestMapping(params = "csvOut", produces = "text/csv")
public ModelAndView makeCsvOut(HttpServletResponse response, Form form)
        throws JAXBException, IOException {

    // DBから出力する情報を取得してDTOに格納
    CsvOutDTO dto = this.service.geCsvInfo(form);

    // DTOをXMLの形式に変換
    JAXBContext context = JAXBContext.newInstance(CsvOutDTO.class);
    Writer writer = new StringWriter();
    context.createMarshaller().marshal(dto, writer);

    // モデルに変換したXMLを格納
    String xslName = "CsxXsl";
    ModelAndView modelAndView = new ModelAndView(xslName);
    modelAndView.addObject(
        "xmlSource", new StringReader(writer.toString()));

    // HTTPレスポンスヘッダを作成
    response.setHeader("Content-Disposition", 
        "attachment; filename=csvFile.csv, "UTF-8"));

    // BOMを先頭に付加
    response.getOutputStream().write(CxFix.BOM);

    return modelAndView;
}

データベースからCSV出力する内容を取得することを想定しています。
「geCsvInfo」の中身は消略していますが、このメソッドの中身がDBアクセスしてDTOのインスタンスを返却するイメージです。


その後はサンプルの通りで、DTOを「JAXBContext」に渡せば、CSVファイルの出来上がり


次にXSLファイルのサンプルです。

上記のJavaソースで”CsvXsl”という名前で定義されたXSLファイルのサンプルになります。


<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet version="2.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns="http://www.w3.org/1999/xhtml">
    <xsl:output method="text" omit-xml-declaration="yes" 
        byte-order-mark="yes" encoding="UTF-8" />
  <xsl:template match="/csvList">
    <xsl:call-template name="template_csvList" />
  </xsl:template>
    <xsl:template name="template_csvList">
        <!-- ヘッダ情報 -->
        <xsl:text>カラム1,</xsl:text>
        <xsl:text>カラム2,</xsl:text>
        <xsl:text>カラム3,</xsl:text>
        <xsl:text>
    </xsl:text>
        <!-- データ情報 -->
        <xsl:value-of
            select="translate(translate(translate(
                ./entity/col1, '"', ' '), ',', ' '), '', ' ')" />
        <xsl:text>,</xsl:text>
        <xsl:value-of
            select="translate(translate(translate(
                ./entity/col2, '"', ' '), ',', ' '), '', ' ')" />
        <xsl:text>,</xsl:text>
        <xsl:value-of
            select="translate(
                translate(translate(./entity/col3, '"', ' '), 
                ',', ' '), '', ' ')" />
        <xsl:text>,</xsl:text>
    </xsl:template>
</xsl:stylesheet>

「entity」とは、前のJavaコードに記載していた、「CsvOutDTO」で使用しているエンティティクラスです。
1行データ毎に1エンティティのレコードを保持します。


CSVファイルは1行目は各項目名の説明で、実際のデータ出力は2行目からです。
XSLファイルで2行目以降を動的にすることで、「CsvOutDTO」に格納されているエンティティの数だけCSVデータ出力がおこなわれます


関数は「translate」しか使っていません。
ダブルクオテーションと改行コードを半角スペースに変換しています。


まとめ


いかがでしたでしょうか?


SpringMVCでCSV出力をおこなう場合に、参考にしてもらえればと思います。
特に、XSLの関数は助かります。
ちょっとした処理をJavaでおこなう必要がないので。


それではまた!


sakusaku

都内でSIerをやっています。 使用している技術は、Java、PHP、MySQL、PostgreSQL、Oracle、Apache、Tomcat、あたりです。 Pythonやってみたいです。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

CAPTCHA


このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください