【问题标题】:XSLT allowing mismatched tags?XSLT 允许不匹配的标签?
【发布时间】:2011-04-09 03:45:54
【问题描述】:
<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 中的标签不匹配...还是有其他方法可以达到相同的预期效果?

【问题讨论】:

标签: html xml xslt


【解决方案1】:

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

查看您的模板,您似乎正在尝试使用 XML 实例的所有 &lt;location&gt; 元素构建一个 html 表。您尝试在第一个 &lt;location&gt; 打开表格并尝试在最后一个 &lt;location&gt; 关闭表格。

执行此操作的最简单方法是在更高级别(父/祖先)打开表,然后使用 &lt;location&gt; 数据填充表。

这是一个包含 3 个&lt;location&gt;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>

如果由于某种原因您需要在第一个 &lt;location&gt; 处创建 &lt;table&gt;,您仍然可以这样做。不过这需要更多代码。

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

<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 两种正确方法。请注意,第一个location 规则的内容模板是在not-first 模式规则上复制location 的内容模板。这是 xsl:call-template 指令的正确位置。
  • @Alejandro:出色的观察力。这大大简化了第二个示例。我知道我会错过凌晨 3 点回答问题的内容。再次感谢!
【解决方案2】:

有什么办法允许不匹配 XSLT 中的标签

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

另外,如果&lt;xsl:output&gt;method 属性的值指定为“xml”,那么输出将始终是格式正确的 XML 片段(或文档)。

...或者还有其他方法可以实现 想要的效果一样吗?

如果您定义了要解决的问题,许多人将能够向您展示一个不需要格式错误的 XSLT 的解决方案。

【讨论】:

    【解决方案3】:

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

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

    【讨论】:

      【解决方案4】:

      问题的简化版本,我认为这是一个常见问题。 (我受到建议不要将 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”行。也许有更好的解决方案。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-12-13
        • 1970-01-01
        • 2019-03-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多