2011-04-09 57 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”线。也许有更好的解决方案。