カテゴリー別アーカイブ: XML

XSLT2.0 で XHTML をコピーしたときに余計な名前空間が出ないようにする

久しぶりに NetBSD に Java 処理系をインストールしようとしたら、OpenJDK なるものが(pkgsrcにも)存在することを知った。

このあたりの事情には全く疎かったのだが、今やSunJDKの正式な後継で、かつオープンな Java 処理系という理解で良いのかな?

オープンになったということで、NetBSD でもネイティブに動作するようになっているようだ。ということはLinux エミュレーションは不要ということか。それはめでたい。

そもそも、なんで Java をインストールしようとしていたか(Java のプログラムなど書かないのに)というと、単に XSLT の処理系を動かしたくて、それが Java で書かれているってだけの理由だ。

これまで XSLT の処理系は Xalan というのを
Exslt という XSLT の拡張と組合せて使っていた。Xalan はApache Software Foundation の処理系ということで、なんとなく標準に近そうなイメージで選んでいたのだが、近年は開発が止まっているように見える。同様に、Exslt の開発も止まっている。

今時は何を使うのだろうと思って調べてみると、Saxon とかいうのがよく使われているらしい。

で、OpenJDK とともに Saxon を使ってみた。使用するスタイルシートは Xalan + Exlt 用に書いたもの。

結果は、Exlt は不要、というか、Saxon では Exlt はエラーが出て動かなかった。まあ、Exslt で拡張した関数は、同等のものが組み込みで提供されるので必要なくなっている。

多少の書き換えが必要だったものの、昔のスタイルシートを Saxon で動作させることができた。印象としては、機能が大幅に拡張され、厳密性のチェックは少し厳しくなったような感じ。

ちょっと困ったのが、XML ソースにある XHTML のノードツリーをコピーすると、空の名前空間宣言がついてしまうこと。

<div>
<p>これは<a href="#">サンプルテキスト</a>です。<br />
改行しました。</p>
</div>
<?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="xhtml" version="1.0" encoding="utf-8"
indent="yes" omit-xml-declaration="yes" />
<xsl:template match="/">
<html>
<head><title>タイトル</title></head>
<body>
<xsl:apply-templates />
</body>
</html>
</xsl:template>
<xsl:template match="*">
<xsl:copy>
<xsl:apply-templates select="@*" />
<xsl:apply-templates select="node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="@*|text()">
<xsl:copy />
</xsl:template>
</xsl:stylesheet>
$ openjdk7-java -jar saxon9he.jar -xsl:test.xsl -s:test.xml -o:test.html
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>タイトル</title>
</head>
<body>
<div xmlns="">
<p>これは
<a href="#">サンプルテキスト</a>です。
<br></br>
改行しました。
</p>
</div>
</body>
</html>

見ての通り、ソースからコピーしたノードツリーのトップ div 要素の属性に空のデフォルト名前空間が出力されてしまっている。また、本来短縮形であるはずの br 要素が長形式 “<br></br>” になってしまっている。

IBM のページによれば、こういう時は xsl:copy ではなく xsl:element を使うのが正しいらしい(XSLT2.0の場合)。

<?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="xhtml" version="1.0" encoding="utf-8"
indent="yes" omit-xml-declaration="yes" />
<xsl:template match="/">
<html>
<head><title>タイトル</title></head>
<body>
<xsl:apply-templates />
</body>
</html>
</xsl:template>
<xsl:template match="*">
<xsl:element name="{name()}">
<xsl:apply-templates select="@*" />
<xsl:apply-templates select="node()" />
</xsl:element>
</xsl:template>
<xsl:template match="@*|text()">
<xsl:copy />
</xsl:template>
</xsl:stylesheet>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>タイトル</title>
</head>
<body>
<div>
<p>これは<a href="#">サンプルテキスト</a>です。<br />
改行しました。
</p>
</div>
</body>
</html>

不要な名前空間はなくなり、br 要素も正しく短縮形 “<br />” となった。