2011-09-17 61 views
1

我想不出一種簡單而優雅的方式,使用XPath或簡單的XSLT模板在XML文檔中查找「上一個」和「下一個」元素。下面是一個示例XML文檔(在真實的文件,@id的就不會這麼簡單地訂購)使用XSLT/XPath在文檔中查找上一個/下一個元素

<manual> 
    <section id="1"> 
    <section id="2"> 
     <section id="3"/> 
     <section id="4"/> 
     <section id="5"/> 
    </section> 
    <section id="6"> 
     <section id="7"/> 
     <section id="8"/> 
     <section id="9"/> 
    </section> 
    </section> 
    <section id="10"/> 
    <section id="11"> 
    <section id="12"/> 
    </section> 
</manual> 

這裏就是我的文檔順序意味着先前/隨後

+------------------+------------------+--------------+ 
| Selected section | Previous section | Next section | 
+------------------+------------------+--------------+ 
| 1    | none    | 2   | 
| 2    | 1    | 3   | 
| 3    | 2    | 4   | 
| 4    | 3    | 5   | 
| 5    | 4    | 6   | 
| ...    | ...    | ...   | 
| 10    | 9    | 11   | 
| 11    | 10    | 12   | 
| 12    | 11    | none   | 
+------------------+------------------+--------------+ 

preceding::軸的問題是排除了祖先,即section[id=2]不是section[id=3]的前一個節點。

以相同的方式,following::軸不包括後代,即section[id=3]不是section[id=2]的後續節點。

那麼,我怎麼能產生「上一個」和「下一個」元素,例如從這些模板:

<xsl:template match="section" mode="prev"> 
    <xsl:value-of select="... what to put here ..."/> 
</xsl:template> 

<xsl:template match="section" mode="next"> 
    <xsl:value-of select="... what to put here ..."/> 
</xsl:template> 

注意,這是一個相似但不相同的問題在這裏:XPath 1.0 closest preceding and/or ancestor node with an attribute in a XML Tree。這些XPath的構造是真的結束了我的頭,有時...

+0

將它們與|並選擇第一個 –

+0

@尼古拉斯:工會什麼在一起? '::前::和祖先::'?這對'@ id = 6'不起作用,前面的部分應該是5,我想呢? –

+0

@尼古拉斯,我錯了。看到馬丁的回答。多謝你們! –

回答

1

這裏是結合尼古拉斯建議與工會,然後取last()上一個項目,第一個爲下一個項目使用的樣式表

<xsl:stylesheet 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    version="2.0"> 

    <xsl:output method="html" indent="yes"/> 

    <xsl:template match="manual"> 
    <table> 
     <thead> 
     <tr> 
      <th>Selected section</th> 
      <th>Previous section</th> 
      <th>Next section</th> 
     </tr> 
     </thead> 
     <tbody> 
     <xsl:apply-templates select="descendant::section"/> 
     </tbody> 
    </table> 
    </xsl:template> 

    <xsl:template match="section"> 
    <tr> 
     <td> 
     <xsl:value-of select="@id"/> 
     </td> 
     <xsl:apply-templates select="." mode="prev"/> 
     <xsl:apply-templates select="." mode="next"/> 
    </tr> 
    </xsl:template> 

    <xsl:template match="section" mode="prev"> 
    <td> 
     <xsl:value-of select="(preceding::section | ancestor::section)[last()]/@id"/> 
    </td> 
    </xsl:template> 

    <xsl:template match="section" mode="next"> 
    <td> 
     <xsl:value-of select="(following::section | descendant::section)[1]/@id"/> 
    </td> 
    </xsl:template> 

</xsl:stylesheet> 

與樣品輸入撒克遜6.5.5輸出

<table> 
    <thead> 
     <tr> 
     <th>Selected section</th> 
     <th>Previous section</th> 
     <th>Next section</th> 
     </tr> 
    </thead> 
    <tbody> 
     <tr> 
     <td>1</td> 
     <td></td> 
     <td>2</td> 
     </tr> 
     <tr> 
     <td>2</td> 
     <td>1</td> 
     <td>3</td> 
     </tr> 
     <tr> 
     <td>3</td> 
     <td>1</td> 
     <td>4</td> 
     </tr> 
     <tr> 
     <td>4</td> 
     <td>1</td> 
     <td>5</td> 
     </tr> 
     <tr> 
     <td>5</td> 
     <td>1</td> 
     <td>6</td> 
     </tr> 
     <tr> 
     <td>6</td> 
     <td>1</td> 
     <td>7</td> 
     </tr> 
     <tr> 
     <td>7</td> 
     <td>1</td> 
     <td>8</td> 
     </tr> 
     <tr> 
     <td>8</td> 
     <td>1</td> 
     <td>9</td> 
     </tr> 
     <tr> 
     <td>9</td> 
     <td>1</td> 
     <td>10</td> 
     </tr> 
     <tr> 
     <td>10</td> 
     <td>1</td> 
     <td>11</td> 
     </tr> 
     <tr> 
     <td>11</td> 
     <td>1</td> 
     <td>12</td> 
     </tr> 
     <tr> 
     <td>12</td> 
     <td>1</td> 
     <td></td> 
     </tr> 
    </tbody> 
</table> 
+0

它確實工作!很好,所以我誤解了':: :: ::和':: ::的概念。非常感謝! –

0

A「不那麼優雅」實現將是這個(選擇@id,而不是整個節點)

<xsl:template match="section" mode="prev-id"> 
    <xsl:variable name="id" select="@id"/> 

    <xsl:variable name="position"> 
    <xsl:for-each select="//section"> 
     <xsl:if test="@id = $id"> 
     <xsl:value-of select="position()"/> 
     </xsl:if> 
    </xsl:for-each> 
    </xsl:variable> 

    <xsl:for-each select="//section"> 
    <xsl:if test="position() = $position - 1"> 
     <xsl:value-of select="@id"/> 
    </xsl:if> 
    </xsl:for-each> 
</xsl:template> 

<xsl:template match="section" mode="next-id"> 
    <xsl:variable name="id" select="@id"/> 

    <xsl:variable name="position"> 
    <xsl:for-each select="//section"> 
     <xsl:if test="@id = $id"> 
     <xsl:value-of select="position()"/> 
     </xsl:if> 
    </xsl:for-each> 
    </xsl:variable> 

    <xsl:for-each select="//section"> 
    <xsl:if test="position() = $position + 1"> 
     <xsl:value-of select="@id"/> 
    </xsl:if> 
    </xsl:for-each> 
</xsl:template> 
相關問題