@IT会議室は、ITエンジニアに特化した質問・回答コミュニティ「QA@IT」に生まれ変わりました。ぜひご利用ください。
- PR -

xalanを使ってxslファイルから複数のhtmlを吐き出す

1
投稿者投稿内容
fireworkss
会議室デビュー日: 2007/02/12
投稿数: 11
投稿日時: 2007-02-19 18:15
ご協力お願いします。

下記のようなxmlファイルがあったとして
------------------------------------------------------------
<?xml version="1.0" encoding="UTF-8"?>
<all>
<product file_id="b-00">
<yoso>ああああああああああああああああ</yoso>
</product_category>

<product file_id="b-01">
<yoso>いいいいいいいいいいいいいいいい</yoso>
</product_category>

<product file_id="b-02">
<yoso>うううううううううううううううう</yoso>
</product_category>
</all>
------------------------------------------------------------
たとえば、<product file_id="b-00">〜<product file_id="b-02">の
三つをそれぞれ別のhtmlファイルに分けて出力することは
可能なのでしょうか。
さらに、file_idの部分をhtmlファイル名にしたいと思っています。

xalanでなくてもかまわないので、
ご存知の方、教えていただけますでしょうか。

[ メッセージ編集済み 編集者: fireworkss 編集日時 2007-02-19 18:17 ]
MMX
ぬし
会議室デビュー日: 2001/10/26
投稿数: 861
投稿日時: 2007-02-20 10:43
XSL Transformations (XSLT) Version 1.0
では、複数出力の実装ないのでは、(XSLT2.0 仕様にはある)
xalanの発想は stream/pipe処理でもあるから。

先に分割して 複数回transform か、transform 一本化出力を 後分割の仕組みは
自作になるでしょう。
fireworkss
会議室デビュー日: 2007/02/12
投稿数: 11
投稿日時: 2007-02-21 18:56
ご返答ありがとうございました。
了解しました。
ひだちのいろ
会議室デビュー日: 2007/02/14
投稿数: 9
投稿日時: 2007-02-22 21:51
横レス失礼いたします。
xalanじゃなくて、MSXSLならJScriptを混ぜて次のように書けます。
無理やりなんですが。

== sample.xsl =======================
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" version="1.0">
<!-- 出力モード -->
<xsl:output method="html" encoding="Shift_JIS"/>

<msxsl:script language="JScript" implements-prefix="xmlns">
function putfile(nodeList, filename)
{
// ファイル操作オブジェクト作成
var fso = new ActiveXObject("Scripting.FileSystemObject");

for(var i=0; i<nodeList.length; i++)
{
// 出力すべきノード
var node = nodeList.item(i);

// 変換元XMLファイルのパスを得る
var path = node.ownerDocument.url;
// 「http://」や「file:///」を取り除く。
path = path.replace(/^[^:]+:\\/+/, "");
// 「/」 を 「\\」に
path = path.replace(/\\//g, "\\\\");
// 変換元XMLファイルがあるフォルダのパスを得る。(そこに出力する)
var folder = path.replace(/\\\\[^\\\\]+$/, "");

// ファイルオープン(2=書き込みモード, true=ファイルが無ければ作成する, -1=UTF-16)
var file = fso.OpenTextFile(folder+"\\\\"+filename+".html", 2, true, -1);
// ファイル書き込み
file.Write(nodeList.item(0).xml);
}

// 空文字列でも、なにかしら値を返さなければならない。
return "";
}
</msxsl:script>

<xsl:template match="product">
<xsl:value-of select="xmlns:putfile(., string(@file_id))"/>
『<xsl:value-of select="@file_id"/>.html』を出力しました。<br/>
</xsl:template>

</xsl:stylesheet>
=====================================

== sample.xml =======================
<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="sample.xsl"?>

<all>
<product file_id="b-00">
<yoso>ああああああああああああああああ</yoso>
</product>

<product file_id="b-01">
<yoso>いいいいいいいいいいいいいいいい</yoso>
</product>

<product file_id="b-02">
<yoso>うううううううううううううううう</yoso>
</product>
</all>
=====================================

sample.xmlをInternetExplorerで開くと、JScriptが実行されてHTMLファイルが生成されます。
上のは <product> の中身を個別にHTMLに保存しているだけなので、XSLTを使う旨味はないんですが、

=====================================
<xsl:template match="product">
<xsl:variable name="node">
<html>
<head>
<title><xsl:value-of select="@file_id"/></title>
</head>
<body>
<h1><xsl:value-of select="@file_id"/></h1>
<xsl:apply-templates/>
</body>
</html>
</xsl:variable>
<xsl:value-of select="xmlns:putfile($node, string(@file_id))"/>
『<xsl:value-of select="@file_id"/>.html』を出力しました。<br/>
</xsl:template>
=====================================

<xsl:template match="product">の部分を上のようにすると、XSLT変換の結果を直接ファイルに落とせるので、意味があるかもしれません。
ただ、JScript中でファイル操作を行っているので、ウイルス対策ソフトを入れていると途中で警告が出ると思います。


もう一つこれはxalan向けの方法なんですが、次のように<product>の内容を一つだけ出力するXSLTを作ってやると

== sample2.xsl ======================
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<!-- 出力モード -->
<xsl:output method="html" encoding="Shift_JIS"/>

<xsl:param name="file_id" select="''"/>

<xsl:template match="product">
<xsl:if test="@file_id=$file_id">
<html>
<head>
<title><xsl:value-of select="@file_id"/></title>
</head>
<body>
<h1><xsl:value-of select="@file_id"/></h1>
<xsl:apply-templates/>
</body>
</html>
</xsl:if>
</xsl:template>

</xsl:stylesheet>
=====================================

xalanで変換をするときに指定したファイルIDのものだけ出力するようになるので……

=====================================
java org.apache.xalan.xslt.Process -PARAM file_id b-00 -IN sample.xml -XSL sample2.xsl -OUT result.html
=====================================

という風に -PARAM file_id ... で出力する <product> を選べるようになります。
その上で、

== sample.bat =======================
@ECHO OFF
TYPE sample.xml | FIND "product" > .tmp
FOR /F "tokens=2 delims==>" %%i IN (.tmp) DO (
java org.apache.xalan.xslt.Process -PARAM file_id %%~i -IN sample.xml -XSL sample2.xsl -OUT %%~i.html
@ECHO 変換『%%~i』
)
del .tmp
=====================================

Windows環境ならこんなバッチファイルを用意して、実行する――というのも一つの手かもしれません。
Linux系ならシェルスクリプトでもっとちゃんと書けると思います……。
ひだちのいろ
会議室デビュー日: 2007/02/14
投稿数: 9
投稿日時: 2007-02-22 22:36
ながながと書いた後に申し訳ないのですが、『xalan』には複数ファイル出力のための機能があらかじめ用意されていました……。

== sample3.xsl =============================
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0"
xmlns:redirect="org.apache.xalan.xslt.extensions.Redirect"
extension-element-prefixes="redirect">

<!-- 出力モード -->
<xsl:output method="html" encoding="Shift_JIS"/>

<xsl:template match="product">
<!-- 出力ファイル名 -->
<xsl:variable name="filename" select="concat(@file_id, '.html')"/>
<!-- 出力開始 -->
<redirect:open select="$filename"/>
<redirect:write select="$filename">
<html>
<head>
<title><xsl:value-of select="@file_id"/></title>
</head>
<body>
<h1><xsl:value-of select="@file_id"/></h1>
<xsl:apply-templates/>
</body>
</html>
</redirect:write>
<redirect:close select="$filename"/>
<!-- 変換報告 -->
『<xsl:value-of select="$filename"/>』変換完了
</xsl:template>

</xsl:stylesheet>
============================================

このようなXSLTスクリプトを用意し、

============================================
java org.apache.xalan.xslt.Process -IN sample.xml -XSL sample3.xsl
============================================

で出力が可能です。

<redirect:open>で出力先ファイルを開き、<redirect:write>の中身を出力し、その後<redirect:close>でファイルを閉じます。
3つすべてのタグに「select="ファイル名"」を指定する必要があるようです。
また、ルート要素の「<xsl:stylesheet>」にいくつか属性を指定しないと、この拡張機能は使用できないようです。

============================================
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0"
xmlns:redirect="org.apache.xalan.xslt.extensions.Redirect"
extension-element-prefixes="redirect">
......
============================================

参考:
http://www.atmarkit.co.jp/fxml/tanpatsu/10xslt/xslt07.html
1

スキルアップ/キャリアアップ(JOB@IT)