Markdownの変換結果にgoogle-code-prettifyを組込む
はじめに
google-code-prettifyはhtmlの中に記述したソースコードのシンタックスハイライトモジュールである.予約語やコメントの色を変えて表示してくれるので,ソースコードが見やすくなる.
また,このサイトはMarkdownを使って記述し,それをxhtmlに変換している.Markdownからxhtmlへの変換時に,ソースコードがあったら自動的にgoogle-code-prettifyを組込んでくれると便利だ.そんなことができるxsltを考えてみた.
環境は以下の通り.
- Microsoft Windows XP SP2+セキュリティパッチたくさん
- Cygwin 1.5.24(uname -r で確認)
- Saxon-B 9.0.0.2J
- Markdown 1.0.1
- google-code-prettify 31 Aug 2007
なお,今回はオリジナルのMarkdownを使っているが,PHP MarkdownでもPHP Markdown Extraでも同じやり方で組込み可能である.
Markdownでの記述とxmlへの変換
Markdownでソースコードを記述するには,4文字以上の空白文字またはタブを行頭に記述する.ブロック要素ではない,インライン要素の場合はバッククオート(`)で文字列を囲む.今回はサンプルとして以下のようなファイルを用意した.
sam.md:
perl:
#!/usr/bin/perl -w
use strict;
#comment
print "hello\n"
インラインで書いてあるコード.例えば`print "hello"`.
コマンドライン(Cygwin版bash)から以下のように実行してxhtmlに変換する.なお,Markdownをインストールしたディレクトリを$markdown.home
と表記する.
${markdown.home}/Markdown.pl sam.md>sam.xml
こんな結果になる.
sam.xml:
<p>perl:</p>
<pre><code>#!/usr/bin/perl -w
use strict;
#comment
print "hello\n"
</code></pre>
<p>インラインで書いてあるコード.例えば<code>print "hello"</code>.</p>
ブロック要素のソースコードは<pre><code>
,インライン要素のソースコードは<code>
に変換される.
このままでは,整形式(well-formed)のxmlではないため,xsltでの変換ができない.そこで,ルート要素<root>
を追加する.
sam.xml:
<root>
<p>perl:</p>
<pre><code>#!/usr/bin/perl -w
use strict;
#comment
print "hello\n"
</code></pre>
<p>インラインで書いてあるコード.例えば<code>print "hello"</code>.</p>
</root>
google-code-prettify組込み用xslt
google-code-prettifyを組込むには以下の事を行う必要がある.
- prettify.jsとprettify.cssを読込む
- body要素のonload属性に
prettyPrint();
を追記 - ブロック要素
<pre><code>
の場合はpre要素のclass属性にprettyprint
を指定 - インライン要素
<code>
の場合はcode要素のclass属性にprettyprint
を指定
prettify.js/prettify.cssの読込みとbody要素のonload属性の追記は対象のxmlの中にcode要素がある時だけ行えば良い.また,class属性にprettyprintを指定する場所は,ブロック要素ならpre要素,インライン要素ならcode要素の中である.このあたりに注意して作成したxsltは以下の通り.
sam.xsl:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output
method="xml"
encoding="UTF-8"
indent="no"/>
<xsl:template match="root">
<html>
<head>
<xsl:if test="//code"> <!-- code要素があったら -->
<script type="text/javascript" src="prettify/prettify.js"></script>
<link rel="stylesheet" type="text/css" href="prettify/prettify.css"/>
</xsl:if>
</head>
<body>
<xsl:if test="//code">
<xsl:attribute name="onload">
<xsl:text>prettyPrint();</xsl:text>
</xsl:attribute>
</xsl:if>
<xsl:apply-templates/>
</body>
</html>
</xsl:template>
<xsl:template match="pre[child::code]"> <!-- pre/codeだったらpreのclass属性にprettyprintを指定 -->
<pre class="prettyprint">
<xsl:apply-templates/>
</pre>
</xsl:template>
<xsl:template match="code[not(parent::pre)]"> <!-- codeだったらcodeのclass属性にprettyprintを指定 -->
<code class="prettyprint">
<xsl:apply-templates/>
</code>
</xsl:template>
<xsl:template match="*|@*|text()">
<xsl:copy>
<xsl:apply-templates select="*|@*|text()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
sam.xmlを以下のコマンドで変換する.
java -jar "${saxon_home}/saxon9.jar" -versionmsg:off -s:sam.xml -xsl:sam.xsl
実行結果:
<?xml version="1.0" encoding="UTF-8"?>
<html>
<head>
<script type="text/javascript" src="prettify/prettify.js"/>
<link rel="stylesheet" type="text/css" href="prettify/prettify.css"/>
</head>
<body onload="prettyPrint();">
<p>perl:</p>
<pre class="prettyprint"><code>#!/usr/bin/perl -w
use strict;
#comment
print "hello\n"
</code></pre>
<p>インラインで書いてあるコード.例えば<code class="prettyprint">print "hello"</code>.</p>
</body>
</html>
念のためソースコードのないxml(<pre>
はあるが<code>
はない)も変換してみよう.
sam2.xml
<root>
<p>perl:</p>
<pre>
code要素のないpre
</pre>
文字列.
</root>
sam2.xmlを以下のコマンドで変換する.
java -jar "${saxon_home}/saxon9.jar" -versionmsg:off -s:sam2.xml -xsl:sam.xsl
実行結果:
<?xml version="1.0" encoding="UTF-8"?>
<html>
<head/>
<body>
<p>perl:</p>
<pre>
code要素のないpre
</pre>
文字列.
</body>
</html>
<code>
がないのでgoogle-code-prettify関連の出力はない.