通过XSLT从XML生成有效的EPUB3导航文档

时间:2014-01-29 00:29:40

标签: xslt xslt-2.0 epub3

我正在尝试通过XSLT从XML文件生成EPUB3导航文档。

示例XML:

<div class="toc" id="s1">
    <p class="toc-title">Detailed Contents</p>
    <ul class="toc">
        <li class="toc-item">
            <a class="ref-chap" id="a1" href="#a1">Preface</a>
        </li>
        <li class="book-section">
            <a class="ref-chap" id="a2" href="#a2">
                <b>Part I.</b>
            </a>
            <ul class="book-section">
                <li class="toc-item">
                    <a class="ref-chap" id="a3" href="#a3">
                        <b>Chapter 1</b>
                    </a>
                    <ul class="chapter-section">
                        <li class="toc-item">
                            <a class="ref-chap" id="a4" href="#a4">
                                <b>Sub Chapter a</b>
                            </a>
                            <ul class="chapter-subsection">
                                <li class="toc-item">
                                    <a class="ref-chap" id="a5" href="#a5">Sub Chapter B</a>
                                </li>
                            </ul>
                        </li>
                    </ul>
                </li>
            </ul>
            <ul class="book-section">
                <li class="toc-item">
                    <a class="ref-chap" id="a6" href="#a6">
                        <b>Chapter 2</b>
                    </a>
                    <ul class="chapter-section">
                        <li class="toc-item">
                            <a class="ref-chap" id="a7" href="#a7">
                                <b>Sub Chapter A</b>
                            </a>
                        </li>
                    </ul>
                </li>
            </ul>
        </li>
    </ul>
</div>

需要输出:

<nav xmlns:epub="http://www.idpf.org/2007/ops" epub:type="toc" id="toc">
    <h1>Detailed Contents</h1>
    <ol>
        <li><a href="a1">Preface: To Our Readers</a></li>
        <li><a href="a2"><b>Part I</b></a>
            <ol>
                <li><a href="a3"><b>Chapter 1</b></a>
                    <ol>
                        <li><a href="a4"><b>Sub Chapter A</b></a>
                            <ol>
                                <li><a href="a5">Sub Chapter B</a></li>
                            </ol>
                        </li>
                    </ol>
                </li>
                <li><a href="a6"><b>Chapter 2</b></a>
                    <ol>
                        <li><a href="a7"><b>Sub Chapter A</b></a></li>
                    </ol>
                </li>
            </ol>
        </li>
    </ol>
</nav>

我的问题区域是第一部分的<ol>子项,我需要它在第2章之后关闭,但它在第1章结束后关闭而不是使用以下XSLT。

我的XSLT:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:epub="http://www.idpf.org/2007/ops"
    exclude-result-prefixes="xs epub"
    version="2.0">

    <xsl:output method="xhtml" include-content-type="no" xpath-default-namespace="http://www.w3.org/1999/xhtml" indent="yes"/>

    <xsl:strip-space elements="*"/>

    <xsl:template match="div[@class='toc']">
        <xsl:element name="nav">
            <xsl:attribute name="epub:type" select="'toc'"/>
            <xsl:attribute name="id" select="'toc'"/>
            <xsl:element name="h1">
                <xsl:value-of select="//div[@class='toc']/p[@class='toc-title']"/>
            </xsl:element>
            <xsl:apply-templates/>
        </xsl:element>
    </xsl:template>

    <xsl:template match="div[@class='toc']//ul[@class='toc'] | div[@class='toc']//ul[@class='book-section'] | div[@class='toc']//ul[@class='chapter-section' or @class='chapter-subsection']">
        <xsl:element name="ol">
            <xsl:apply-templates/>
        </xsl:element>
    </xsl:template>

    <xsl:template match="div[@class='toc']//li[@class='toc-item']">
        <xsl:element name="li">
            <xsl:apply-templates/>
        </xsl:element>
    </xsl:template>

    <xsl:template match="div[@class='toc']//li[@class='book-section']">
        <xsl:element name="li">
            <xsl:apply-templates xml:space="default"/>
        </xsl:element>
    </xsl:template>

    <xsl:template match="a[@class='ref-chap']">
        <xsl:element name="a">
            <xsl:attribute name="href" select="concat(substring-after(@href, '#'),'.xhtml')"/>
            <xsl:apply-templates/>
        </xsl:element>
    </xsl:template>

    <xsl:template priority="1" match="ul[@class='chapter-section' or @class='chapter-subsection']//a[@class='ref-chap']">
        <xsl:variable name="pagenumber" select="following-sibling::a[@class='page-ref']"/>
        <xsl:element name="a">
            <xsl:attribute name="href" select="concat(substring-after(ancestor::ul[@class='chapter-section'][1]/preceding-sibling::a[@class='ref-chap'][1]/@href, '#'),'.xhtml','#page',$pagenumber)"/>
            <xsl:apply-templates/>
        </xsl:element>
    </xsl:template>

</xsl:stylesheet>

给我一​​个无效的EPUB3导航文档:

<nav xmlns:epub="http://www.idpf.org/2007/ops" epub:type="toc" id="toc">
   <h1>Detailed Contents</h1>Detailed Contents
   <ol>
      <li>
         <a href="a1.xhtml">Preface</a>
      </li>
      <li>
         <a href="a2.xhtml">Part I.</a>
         <ol>
            <li>
               <a href="a3.xhtml">Chapter 1</a>
               <ol>
                  <li>
                     <a href="a3.xhtml#page">Sub Chapter a</a>
                     <ol>
                        <li>
                           <a href="a3.xhtml#page">Sub Chapter B</a>
                        </li>
                     </ol>
                  </li>
               </ol>
            </li>
         **</ol>
         <ol>**
            <li>
               <a href="a6.xhtml">Chapter 2</a>
               <ol>
                  <li>
                     <a href="a6.xhtml#page">Sub Chapter A</a>
                  </li>
               </ol>
            </li>
         </ol>
      </li>
   </ol>
</nav>

添加了强调**以表明这些标签是问题所在。它们不应该在输出中。

1 个答案:

答案 0 :(得分:3)

您要做的是将 ul [@ class ='book-section'] 组合在一起。

有不同的方法可以做到这一点,一种方法是在li [@ class ='book-section']的父模板中使用for-each-group,这样你就可以将该模板更改为:

<xsl:template match="div[@class='toc']//li[@class='book-section']">
    <xsl:element name="li">
        <xsl:apply-templates select="xhtml:a[@class='ref-chap']"/>
        <xsl:for-each-group select="ul[@class='book-section']" group-by="@class">
            <ol>
                <xsl:apply-templates select="current-group()/node()"/>
            </ol>
        </xsl:for-each-group> 
    </xsl:element>
</xsl:template>

另一种方法是只匹配ul [@ class ='book-section']中的第一个,然后将其应用于以下的孩子,如下所示:

<xsl:template match="div[@class='toc']//ul[@class='book-section'][1]">
    <xsl:element name="ol">
        <xsl:apply-templates select="* | following-sibling::ul[@class='book-section']/*"/>
    </xsl:element>
</xsl:template>