在嵌套的项列表中选择节点的属性

时间:2013-12-10 18:10:14

标签: xslt xpath xslt-2.0

我有目录的XML。我正在从列表中为XML中的每个锚点生成命名的.xhtml页面。

TOC的结构包含章节,其中还列出了这些章节中的子章节。我试图使用前一章锚的@href值动态命名这些子锚点。

示例XML:

<div class="toc" id="s9781483331812.i34"><a class="page" id="pbr-v" title="v"/>
<p class="toc-title">Contents</p>
<ul class="toc">
        <li class="toc-item">
            <a class="ref-chap" href="#s132" id="s35"><b>Preface</b></a>
            <a class="page-ref" href="#pbr-vii" id="s36"><b>vii</b></a>
        </li>
        <li class="toc-item">
            <a class="ref-chap" href="#s135" id="s37"><b>Introduction</b></a>
            <a class="page-ref" href="#pbr-xi" id="s38"><b>xi</b></a>
        </li>
        <li class="toc-item">
            <span class="toc-label" title="1"><b>1.</b></span>
            <a class="ref-chap" href="#s147" id="s39"><b>Chapter</b></a>  
            <a class="page-ref" href="#pbr-1" id="s40"><b>1</b></a>
            <ul class="chapter-section">
                <li class="toc-item"> 
                    <a class="ref-chap" href="#s152" id="s41">Subsection 1</a>  
                    <a class="page-ref" href="#pbr-2" id="s42">2</a>
                </li>
                <li class="toc-item"> 
                    <a class="ref-chap" href="#s158" id="s43">Subsection 2</a>  
                    <a class="page-ref" href="#pbr-6" id="s44">6</a>
                </li>
                <li class="toc-item"> 
                    <a class="ref-chap" href="#s159" id="s45">Subsection 3</a>  
                    <a class="page-ref" href="#pbr-10" id="s46">10</a>
                </li>
            </ul>
        </li>
    </ul>

示例XSLT:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs"
version="2.0">


<xsl:template match="node()|@*">
    <xsl:copy>
        <xsl:apply-templates select="node()|@*"/>
    </xsl:copy>        
</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="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']//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='toc']//li[@class='toc-item']//a[@class='ref-chap'][last()]/@href, '#'),'.xhtml','#page',$pagenumber)"/>
        <xsl:apply-templates/>
    </xsl:element>
</xsl:template>

我想要的输出是:

<div class="toc" id="s9781483331812.i34">
<a class="page" id="pbr-v" title="v"/>
<p class="toc-title">Contents</p>
<ul class="toc">
        <li>
            <a href="s132.xhtml"><b>Preface</b></a>
            <a class="page-ref" href="#pbr-vii" id="s36"><b>vii</b></a>
        </li>
        <li>
            <a href="s135.xhtml"><b>Introduction</b></a>
            <a class="page-ref" href="#pbr-xi" id="s38"><b>xi</b></a>
        </li>
        <li>
            <span class="toc-label" title="1"><b>1.</b></span>
            <a href="s147.xhtml"><b>Chapter</b></a>  
            <a class="page-ref" href="#pbr-1" id="s40"><b>1</b></a>
            <ul class="chapter-section">
                <li> 
                    <a href="s147.xhtml#page2">Subsection 1</a>  
                    <a class="page-ref" href="#pbr-2" id="s42">2</a>
                </li>
                <li> 
                    <a href="s147.xhtml#page6">Subsection 2</a>  
                    <a class="page-ref" href="#pbr-6" id="s44">6</a>
                </li>
                <li> 
                    <a href="s147.xhtml#page10">Subsection 3</a>  
                    <a class="page-ref" href="#pbr-10" id="s46">10</a>
                </li>
            </ul>
        </li>
    </ul>

我收到错误“不允许多个项目的序列作为substring-after()的第一个参数(”#s132“,”#s135“,...)”。显然我的XPath正在选择多个值而不是一个。但是,我无法弄清楚如何解决这个问题。

注意:章节小节的数量是未知的,可能会有所不同。

1 个答案:

答案 0 :(得分:1)

您的XPath表达式

ancestor::ul[@class='toc']//li[@class='toc-item']//a[@class='ref-chap'][last()]/@href

肯定会捡到太多 - 它会查看toc中所有ref-chap列表项内的所有toc-item个锚点,并给出一个由最后一个锚点组成的序列ref-chap在他们各自的父母里面。由于没有toc-item包含多个ref-chap,这意味着所有

鉴于您目前处于特定ref-chap的上下文中,您无需一直走到toc级别,您只需要向上移动到最近的chapter-section级别ref-chap ul元素,然后拉出该元素最近的前一个兄弟ancestor::ul[@class='chapter-section'][1]/preceding-sibling::a[@class='ref-chap'][1]/@href

ancestor::

请注意,由于preceding-sibling::[1]是反向轴,因此“最近”匹配项(即文档顺序中的最后一项)为{{1}}。