Как сказал Димитр, в XSLT нет способа разрешить несовпадающие теги. Однако не должно быть причины иметь несовпадающие теги.
Глядя на ваш шаблон, похоже, что вы пытаетесь создать HTML-таблицу из всех <location>
элементов вашего экземпляра XML. Вы пытаетесь открыть стол в первый <location>
и пытаетесь закрыть стол в последний <location>
.
Самый простой способ сделать это - открыть таблицу на более высоком уровне (родитель / предок), а затем заполнить таблицу данными <location>
.
Вот пример XML-файла, который имеет 3 <location>
s:
<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>