今回は労働基準法令の中でもひときわ大部である、労働安全衛生規則を変換してみることにした。前回にも書いたように、労働安全衛生規則(以下「規則」とする)は、編、章、節、款といった様々な構成単位により成っていて、また、規則全体を木構造とみなすと、ノードによって深さがまちまち(つまり節のない章や款の無い節がある)だったりするので、割と扱いが面倒なのだった。というわけで僕のプログラミング力では冗長なコードしか書けなかったのだが、まあとりあえず出力自体は成功した。リンクのid名もとりあえずちゃんと付けられた。結果はこちら。
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions" exclude-result-prefixes="xsl xs fn">
<xsl:output method="html"/>
<xsl:template match="/">
<xsl:apply-templates select="Law/LawBody"/>
</xsl:template>
<xsl:template match="Law/LawBody">
<html>
<head>
<title><xsl:value-of select="LawTitle"/></title>
<link href="sample.css" rel="stylesheet" type="text/css" />
</head>
<body>
<h1><xsl:value-of select="LawTitle"/></h1>
<div class="TOC">
<xsl:for-each select="TOC/TOCPart">
<a>
<xsl:attribute name="href">#p<xsl:value-of select="@Num"/></xsl:attribute>
<xsl:value-of select="PartTitle"/>
</a>
<xsl:for-each select="TOCChapter">
<a>
<xsl:attribute name="href">#p<xsl:value-of select="../@Num"/>c<xsl:value-of select="@Num"/></xsl:attribute>
<xsl:attribute name="class">chapter</xsl:attribute>
<xsl:value-of select="ChapterTitle"/><xsl:value-of select="ArticleRange"/>
</a>
<xsl:if test="count(TOCSection)!=0">
<xsl:apply-templates select="TOCSection"/>
</xsl:if>
</xsl:for-each>
</xsl:for-each>
</div>
<xsl:for-each select="MainProvision/Part">
<h2>
<xsl:attribute name="id">p<xsl:value-of select="@Num"/></xsl:attribute>
<xsl:value-of select="PartTitle"/>
</h2>
<xsl:for-each select="Chapter">
<div class="chapter">
<h3 class="chapter_title">
<xsl:attribute name="id">p<xsl:value-of select="../@Num"/>c<xsl:value-of select="@Num"/></xsl:attribute>
<xsl:value-of select="ChapterTitle"/>
</h3>
<xsl:choose>
<xsl:when test="count(Section)=0">
<xsl:apply-templates select="Article"/>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="Section"/>
</xsl:otherwise>
</xsl:choose>
</div>
</xsl:for-each>
</xsl:for-each>
</body>
</html>
</xsl:template>
<xsl:template match="TOCSection">
<a>
<xsl:attribute name="href">#p<xsl:value-of select="../../@Num"/>c<xsl:value-of select="../@Num"/>s<xsl:value-of select="@Num"/></xsl:attribute>
<xsl:attribute name="class">section</xsl:attribute>
<xsl:value-of select="SectionTitle"/><xsl:value-of select="ArticleRange"/>
</a>
<xsl:if test="count(TOCSubsection)!=0">
<xsl:apply-templates select="TOCSubsection"/>
</xsl:if>
</xsl:template>
<xsl:template match="TOCSubsection">
<a>
<xsl:attribute name="href">#p<xsl:value-of select="../../../@Num"/>c<xsl:value-of select="../../@Num"/>s<xsl:value-of select="../@Num"/>ss<xsl:value-of select="@Num"/></xsl:attribute>
<xsl:attribute name="class">subsection</xsl:attribute>
<xsl:value-of select="SubsectionTitle"/><xsl:value-of select="ArticleRange"/>
</a>
</xsl:template>
<xsl:template match="Section">
<div class="section">
<h4 class="section_title">
<xsl:attribute name="id">p<xsl:value-of select="../../@Num"/>c<xsl:value-of select="../@Num"/>s<xsl:value-of select="@Num"/></xsl:attribute>
<xsl:value-of select="SectionTitle"/>
</h4>
<xsl:choose>
<xsl:when test="count(Subsection)=0">
<xsl:apply-templates select="Article"/>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="Subsection"/>
</xsl:otherwise>
</xsl:choose>
</div>
</xsl:template>
<xsl:template match="Subsection">
<h5 class="subsection_title">
<xsl:attribute name="id">p<xsl:value-of select="../../../@Num"/>c<xsl:value-of select="../../@Num"/>s<xsl:value-of select="../@Num"/>ss<xsl:value-of select="@Num"/></xsl:attribute>
<xsl:value-of select="SubsectionTitle"/>
</h5>
<xsl:apply-templates select="Article"/>
</xsl:template>
<xsl:template match="Article">
<div class="article">
<h6 class="article_title"><xsl:value-of select="ArticleTitle"/></h6>
<span class="caption"><xsl:value-of select="ArticleCaption"/></span>
<xsl:apply-templates select="Paragraph"/>
</div>
</xsl:template>
<xsl:template match="Paragraph">
<p class="paragraph">
<xsl:value-of select="ParagraphNum"/>
<xsl:value-of select="ParagraphSentence/Sentence"/>
</p>
<xsl:apply-templates select="Item"/>
</xsl:template>
<xsl:template match="Item">
<p class="item">
<xsl:value-of select="ItemTitle"/>
<xsl:value-of select="ItemSentence/Sentence"/>
<xsl:apply-templates select="ItemSentence/Column"/>
</p>
</xsl:template>
<xsl:template match="ItemSentence/Column">
<xsl:value-of select="Sentence"/>
</xsl:template>
</xsl:stylesheet>
同じコードで民法なんかも変換できるかな~と思って変換したところ、概ね上手く行っていたのだが、恐ろしいことに民法には款より下位の構成単位として「目」というのがあるみたいで、そこは当然ながら出力してくれなかった。まあちょっと修正すれば解決することなのだが、当分の目的は上記コードで果たせるのでとりあえずこれでよしとした。
課題としては、最初に言った通りコードが冗長で、割と再帰でできそうなことをベタベタに処理していてエレガンスに欠けることとかだろうか。XSLTで再帰的なことができるのかは不明だが、もっとスッキリしたコードが書けたらなあ、などと思うのであった。
