<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
	xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
	xmlns:dn="http://www.lcv.ne.jp/~denori"
	exclude-result-prefixes="dn"
	xmlns="http://www.w3.org/1999/xhtml">

<!--
構造化のアルゴリズムは、jintrickさんのものを使わせて頂き(感謝)、
それを自分なりに咀嚼して改造し、新たな機能を付けたモジュールです。

- 使い方 -
http://www.lcv.ne.jp/~denori/diary/diary0406.htm#D040605

[ version 2004.07.02 ]
-->


<xsl:template match="*" mode="dn:structure">
	<!-- 終わり要素の名前空間 -->
	<xsl:param name="endNS" select="'http://www.lcv.ne.jp/~denori'"/>
	<xsl:param name="precedingHeadings"/>
			
	<!-- 現在の見出しか終わりレベル -->
	<xsl:variable name="level">
		<xsl:choose>
			<xsl:when test="namespace-uri() = $endNS">
				<xsl:value-of select="@h"/>
			</xsl:when>
			<xsl:otherwise>
				<xsl:value-of select="substring(local-name(),2)"/>
			</xsl:otherwise>
		</xsl:choose>
	</xsl:variable>
	
	<!-- 現在の見出しより後続にある見出しと終わり要素の集合 -->
	<xsl:variable name="followingHeadings" select="following-sibling::*[(substring(local-name(),1,1) = 'h' and boolean(number(substring(local-name(),2)))) or (local-name() = 'end' and namespace-uri() = $endNS)]"/>
	
	<xsl:choose>
		
		<!-- 見出し要素だったら -->
		<xsl:when test="namespace-uri() != $endNS">
			
			<div>
				<xsl:attribute name="class">
					<xsl:value-of select="concat('section',$level)"/>
				</xsl:attribute>
				<xsl:if test="@id">
						<xsl:attribute name="id">
						<xsl:value-of select="@id"/>
					</xsl:attribute>
				</xsl:if>
				
				<xsl:apply-templates select="self::node()"/>
				
				<!-- 次の見出しか終わり要素が出現するまで出力 -->
				<xsl:call-template name="dn:content">
					<xsl:with-param name="endNS" select="$endNS"/>
				</xsl:call-template>
				
				<xsl:call-template name="dn:heading">
					<xsl:with-param name="endNS" select="$endNS"/>
					<xsl:with-param name="level" select="number($level)"/>
					<xsl:with-param name="followingHeadings" select="$followingHeadings"/>
				</xsl:call-template>
			</div>
		</xsl:when>
		
		<xsl:otherwise>
		
			<!-- 検証用
			<structure-out>
				<headings><xsl:value-of select="string($precedingHeadings)"/></headings>
				<position><xsl:value-of select="position()"/></position>
				<prevhead><xsl:value-of select="substring(string($precedingHeadings),position() - 1,1)"/></prevhead>
				<nextlevel><xsl:value-of select="substring(local-name($followingHeadings[namespace-uri() != $endNS][position() = 1]),2)"/></nextlevel>
				<isheadings><xsl:value-of select="count($followingHeadings[namespace-uri() != $endNS])"/></isheadings>
				<boolean><xsl:value-of select="(position() != 1 and substring(string($precedingHeadings),position() - 1,1) = '*') and (number(substring(local-name($followingHeadings[namespace-uri() != $endNS][position() = 1]),2)) &lt;= number($level) or not(boolean($followingHeadings[namespace-uri() != $endNS])))"/></boolean>
			</structure-out>
			-->	
			
			<!-- 終わり要素のh属性の値が妥当であるか否か
			  [妥当の条件]  以下の2つの条件を満たす事
			    (1)同じセクション内にあって、これより前にh属性値と同位で、且つ、対になった見出しがある($precedingHeadindsを参照して)
			    (2)これより後にh属性値より下位の見出しが無い、若しくは、これ以降見出しが全く無い($followingHeadindsを参照して)
			-->
			<xsl:if test="(position() != 1 and substring($precedingHeadings,position() - 1,1) = '*') and (number(substring(local-name($followingHeadings[namespace-uri() != $endNS][position() = 1]),2)) &lt;= number($level) or not(boolean($followingHeadings[namespace-uri() != $endNS])))">
				<xsl:call-template name="dn:content">
					<xsl:with-param name="endNS" select="$endNS"/>
				</xsl:call-template>
			</xsl:if>
		</xsl:otherwise>
		
	</xsl:choose>
</xsl:template>


<xsl:template name="dn:content">
	<xsl:param name="endNS"/>
	
	<xsl:for-each select="following-sibling::*[position() = 1][(substring(local-name(),1,1) != 'h' or not(boolean(number(substring(local-name(),2))))) and  not(local-name() = 'end' and namespace-uri() = $endNS)]">
			<xsl:apply-templates select="self::node()"/>
			<xsl:call-template name="dn:content">
				<xsl:with-param name="endNS" select="$endNS"/>
			</xsl:call-template>
	</xsl:for-each>
</xsl:template>


<xsl:template name="dn:heading">
	<xsl:param name="endNS"/>
	<xsl:param name="level"/>
	<xsl:param name="followingHeadings"/>
	
	<!-- 同・上位の見出し、及び次下位の見出しと終わり要素の出現情報 -->
	<xsl:variable name="headingsInfo">
		<xsl:for-each select="$followingHeadings">
			<xsl:choose>
				<!-- 同・上位の見出しの、$follwingheadings内での位置情報 -->
				<xsl:when test="number(substring(local-name(),2)) &lt;= $level">
					<xsl:value-of select="concat(':',position(),':')"/>
				</xsl:when>
				<xsl:when test="number(substring(local-name(),2)) = $level + 1">
					<xsl:value-of select="'*'"/>
				</xsl:when>
				<xsl:when test="namespace-uri() = $endNS and @h = $level + 1">
					<xsl:value-of select="'^'"/>
				</xsl:when>
			</xsl:choose>
		</xsl:for-each>
	</xsl:variable>
	
	<!-- 次にある同上位の見出しの位置 -->
	<xsl:variable name="following_position">
		<xsl:choose>
			<xsl:when test="contains(string($headingsInfo),':')">
				<xsl:value-of select="substring-before(substring-after(string($headingsInfo),':'),':')"/>
			</xsl:when>
			<xsl:otherwise>
				<!-- 無ければ、集合の合計数 -->
				<xsl:value-of select="count($followingHeadings)"/>
			</xsl:otherwise>
		</xsl:choose>
	</xsl:variable>
	
	<!-- 検証用
	<heading-out>
		<headings><xsl:value-of select="count($followingHeadings)"/></headings>
		<info><xsl:value-of select="$headingsInfo"/></info>
		<position><xsl:value-of select="$following_position"/></position>
	</heading-out>
	-->	
	
	<!-- 現在の見出しと次の同・上位の見出しの間にある、次下位の見出しと終わりの集合を、セクションの内容として再帰処理 -->
	<xsl:apply-templates select="$followingHeadings[position() &lt;= number($following_position)][local-name() = concat('h',string($level + 1)) or namespace-uri() = $endNS and @h = $level + 1]" mode="dn:structure">
		<xsl:with-param name="endNS" select="$endNS"/>
		
		<!-- 次下位の見出しと終わり要素出現情報だけ渡す -->
		<xsl:with-param name="precedingHeadings" select="translate($headingsInfo,'0123456789:','')"/>
	</xsl:apply-templates>
</xsl:template>


<xsl:template match="*">
	<xsl:element name="{local-name()}">
		<xsl:apply-templates select="@* | child::node()" />
	</xsl:element>
</xsl:template>


<xsl:template match="@* | text()">
	<xsl:copy-of select="self::node()"/>
</xsl:template>

</xsl:stylesheet>

