2011-04-09 56 views
3
<xsl:template match="location"> 
     <xsl:if test="not(preceding::location)"> 
      <table> 
       <tr> 
        <th>Name</th> 
        <th>City</th> 
        <th>State</th> 
        <th>Zip Code</th> 
        <th>Country</th> 
       </tr> 
     </xsl:if> 
     <tr> 
      <td><xsl:value-of select=".//name"/></td> 
      <td><xsl:value-of select=".//city"/></td> 
      <td><xsl:value-of select=".//state"/></td> 
      <td><xsl:value-of select=".//zip"/></td> 
      <td><xsl:value-of select=".//countdy"/></td> 
     </tr> 
     <xsl:if test="not(following::location)"> 
      </table> 
     </xsl:if> 
    </xsl:template> 

是否允許在XSLT中允許不匹配標籤的任何方式......或者是否有另一種方法來實現相同的預期效果?XSLT允許不匹配的標籤?

+0

可能重複的[XSLT:打開但不關閉標記](http://stackoverflow.com/questions/2872396/xslt-opening-but-not-closing-tags) – 2011-04-09 14:07:22

+0

And also http://stackoverflow.com/questions/3701708/how-can-i-print-a-single-div-without-closing-it-in-xslt,and http://stackoverflow.com/questions/2202377/xslt-dynamically-start-and- close-tags,... – 2011-04-09 14:16:45

回答

5

像Dimitre說的那樣,在XSLT中沒有辦法允許不匹配的標籤。不應該有理由有不匹配的標籤。

看着你的模板,它看起來像你試圖從XML實例的所有<location>元素中構建一個html表。您正嘗試在第一個<location>打開表格並試圖在最後的<location>關閉表格。

最簡單的方法是在較高級別(父/祖先)下打開表格,然後用<location>數據填充表格。

下面是一個有3 <location>個示例XML文件:

<doc> 
    <location> 
    <name>name 1</name> 
    <city>city 1</city> 
    <state>state 1</state> 
    <zip>zip 1</zip> 
    <country>country 1</country> 
    </location> 
    <location> 
    <name>name 2</name> 
    <city>city 2</city> 
    <state>state 2</state> 
    <zip>zip 2</zip> 
    <country>country 2</country> 
    </location> 
    <location> 
    <name>name 3</name> 
    <city>city 3</city> 
    <state>state 3</state> 
    <zip>zip 3</zip> 
    <country>country 3</country> 
    </location> 
</doc> 

下面是將創建表樣式表:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output indent="yes"/> 
    <xsl:strip-space elements="*"/> 

    <xsl:template match="doc"> 
    <!--The table is inserted here.--> 
    <table> 
     <tr> 
     <th>Name</th> 
     <th>City</th> 
     <th>State</th> 
     <th>Zip Code</th> 
     <th>Country</th> 
     </tr> 
     <!--This is where we apply the templates to populate the rows.--> 
     <xsl:apply-templates select="location"/> 
    </table> 
    </xsl:template> 

    <!--This template populates the row(s).--> 
    <xsl:template match="location"> 
    <tr> 
     <td> 
     <xsl:value-of select="name"/> 
     </td> 
     <td> 
     <xsl:value-of select="city"/> 
     </td> 
     <td> 
     <xsl:value-of select="state"/> 
     </td> 
     <td> 
     <xsl:value-of select="zip"/> 
     </td> 
     <td> 
     <xsl:value-of select="country"/> 
     </td> 
    </tr> 
    </xsl:template> 

</xsl:stylesheet> 

這是輸出:

<table> 
    <tr> 
     <th>Name</th> 
     <th>City</th> 
     <th>State</th> 
     <th>Zip Code</th> 
     <th>Country</th> 
    </tr> 
    <tr> 
     <td>name 1</td> 
     <td>city 1</td> 
     <td>state 1</td> 
     <td>zip 1</td> 
     <td>country 1</td> 
    </tr> 
    <tr> 
     <td>name 2</td> 
     <td>city 2</td> 
     <td>state 2</td> 
     <td>zip 2</td> 
     <td>country 2</td> 
    </tr> 
    <tr> 
     <td>name 3</td> 
     <td>city 3</td> 
     <td>state 3</td> 
     <td>zip 3</td> 
     <td>country 3</td> 
    </tr> 
</table> 

如果由於某種原因,您需要在第一個創建,你仍然可以這樣做。這需要更多的代碼。

以下樣式表產生輸出作爲第一樣式相同:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output indent="yes"/> 
    <xsl:strip-space elements="*"/> 

    <xsl:template match="/doc"> 
    <xsl:apply-templates/> 
    </xsl:template> 

    <!--The table is created at the first location and 
    the first row is populated.--> 
    <xsl:template match="location[1]"> 
    <table> 
     <tr> 
     <th>Name</th> 
     <th>City</th> 
     <th>State</th> 
     <th>Zip Code</th> 
     <th>Country</th> 
     </tr> 
     <xsl:call-template name="location-row"/> 
     <!--Here is where we apply the other template to populate the other rows. 
     Notice we use a "mode" to differentiate the template from the generic 
     "location" template.--> 
     <xsl:apply-templates select="following-sibling::location" mode="not-first"/> 
    </table> 
    </xsl:template> 

    <!--This template will output the other rows.--> 
    <xsl:template match="location" mode="not-first" name="location-row"> 
    <tr> 
     <td> 
     <xsl:value-of select="name"/> 
     </td> 
     <td> 
     <xsl:value-of select="city"/> 
     </td> 
     <td> 
     <xsl:value-of select="state"/> 
     </td> 
     <td> 
     <xsl:value-of select="zip"/> 
     </td> 
     <td> 
     <xsl:value-of select="country"/> 
     </td> 
    </tr> 
    </xsl:template> 

    <!--This generic template matches locations other than the first one. 
    Basically it is consuming it so we don't get duplicate output.--> 
    <xsl:template match="location"/> 

</xsl:stylesheet> 
+0

+1兩種正確的方法。請注意,第一個'location'規則的內容模板是在'not-first'模式規則中複製'location'的內容模板。這是'xsl:call-template'指令的正確位置。 – 2011-04-09 14:02:34

+0

@Ajjandro:出色的觀察。這大大簡化了第二個例子。我知道我會錯過在凌晨3點回答問題的事情。再次感謝! – 2011-04-09 18:21:01

3

是的任何方式,允許在XSLT

沒有不匹配 標籤。

XSLT樣式表必須是格式良好的XML文檔

另外,如果屬性的值<xsl:output>被指定爲「xml」,那麼輸出將始終是格式良好的XML片段(或文檔)。

...還是有另一種方式實現 相同的預期效果?

如果您定義了要解決的問題,很多人將能夠向您展示解決方案,而不需要格式錯誤的XSLT。

3

記住XSLT建立一個樹 - 在樣式表中的元素節點是一個不可分割的指令寫入到結果樹一個不可分割的元件節點;您不能將樣式表中的開始標記視爲向輸出寫入開始標記的指令,並且樣式表中的結束標記是將結束標記寫入輸出的指令。

通常當我們看到這種東西時(當我們開始使用該語言時,大多數人都會嘗試這種方式),它試圖按照您使用將XML寫爲文本的過程語言進行分組。您需要進入XSLT思維模式,特別是將XML視爲一棵樹。

0

該問題的簡化版本,我認爲這是一個常見問題。 (我的靈感來自於建議不要將XSLT作爲一種過程語言來使用,以前用蠻力來解決它。)

基本上,我想用PRE標記括起代碼行,用於HTML輸出和代碼的第一行有一個獨特的風格:

<xsl:variable name="new_line" select="'&#xA;'"/> 

<xsl:template match="//text:p[@text:style-name='Code_20_Block_20_Beg']"> 
    <PRE> 
    <xsl:for-each select="//text:p[@text:style-name='Code_20_Block']"> 
<xsl:apply-templates/><xsl:value-of select="$new_line"/> 
    </xsl:for-each> 
    </PRE> 
</xsl:template> 


<xsl:template match="//text:p[@text:style-name='Code_20_Block']"> 
</xsl:template> 

我不得不使用一個空的模板(末)忽略那些已經由for-each循環處理「Code_20_Block」線。也許有更好的解決方案。