<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中使用不匹配的标签...或者是否有其他方法可以达到相同的预期效果?
答案 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="'
'"/>
<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'行。也许有更好的解决方案。