XSLT允许不匹配的标签?

时间:2011-04-09 03:45:54

标签: html xml xslt

<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中使用不匹配的标签...或者是否有其他方法可以达到相同的预期效果?

4 个答案:

答案 0 :(得分:5)

就像Dimitre所说,没有办法在XSLT中允许不匹配的标签。不过应该没有理由让标签不匹配。

查看您的模板,看起来您正在尝试从XML实例的所有<location>元素中构建一个html表。您正尝试在第一个<location>打开表格并尝试在最后<location>关闭该表格。

最简单的方法是在更高级别(父级/祖级)打开您的表格,然后使用<location>数据填充表格。

这是一个包含3 <location> s的示例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>

如果出于某种原因需要在第一个<table>创建<location>,您仍然可以这样做。但它需要更多代码。

以下样式表生成与第一个样式表相同的输出:

<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>

答案 1 :(得分:3)

  

是否允许不匹配的任何方式   XSLT中的标签

XSLT样式表必须是格式良好的XML文档

此外,如果method的{​​{1}}属性的值被指定为“xml”,则输出将始终是格式良好的XML片段(或文档)。

  

......还是有其他方法可以实现   同样的预期效果?

如果您定义要解决的问题,很多人都可以向您展示解决方案,不需要格式错误的XSLT。

答案 2 :(得分:3)

请记住,XSLT构建了一个树 - 样式表中的一个元素节点是一个不可分割的指令,用于将不可分割的元素节点写入结果树;你不能认为样式表中的开始标记是将开始标记写入输出的指令,样式表中的结束标记是将结束标记写入输出的指令。

通常当我们看到这种事情(我们大多数人在开始使用该语言时都尝试过它)时,尝试使用将XML作为文本编写的过程语言来进行分组。您需要深入了解XSLT思维模式,特别是将XML视为树。

答案 3 :(得分: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'行。也许有更好的解决方案。