Как и в этом вопросе (есть больше связанных записей, однако, как новый пользователь, я могу опубликовать только один URL):
Xpath Получить элементы, которые находятся между 2 элементами
У меня есть вопрос, касающийся выбора набора элементов, которые встречаются между «другими / разграничивающими» элементами. Такая ситуация возникает при попытке преобразования плоской таблицы HTML в
иерархическая структура XML с использованием XSLT. Я пытался использовать рекурсию в шаблонах, но Саксон отказался принять это, поскольку это привело к взаимоблокировке, скорее всего, по моей вине, но давайте начнем с самого начала.
Сначала исходными данными является таблица HTML:
<table >
<thead>
<tr>
<th>Column 1</th>
<th>Column 2</th>
<th>Column 3</th>
</tr>
</thead>
<tbody>
<tr>
<th colspan="3" >Group 1</th>
</tr>
<tr>
<td>attribute 1.1.1</td>
<td>attribute 1.1.3</td>
<td>attribute 1.1.2</td>
</tr>
<tr>
<td>attribute 1.2.1</td>
<td>attribute 1.2.2</td>
<td>attribute 1.2.3</td>
</tr>
<tr>
<td>attribute 1.3.1</td>
<td>attribute 1.3.2</td>
<td>attribute 1.3.3</td>
</tr>
<tr>
<th colspan="3" >Group 2</th>
</tr>
<tr>
<td>attribute 2.1.1</td>
<td>attribute 2.1.3</td>
<td>attribute 2.1.2</td>
</tr>
<tr>
<td>attribute 2.2.1</td>
<td>attribute 2.2.2</td>
<td>attribute 2.2.3</td>
</tr>
<tr>
<td>attribute 2.3.1</td>
<td>attribute 2.3.2</td>
<td>attribute 2.3.3</td>
</tr>
</tbody>
</table>
Целевой вывод в XML будет:
<groups>
<group name="Group 1">
<item attribute1="attribute 1.1.1" attribute2="attribute 1.1.3" attribute3="attribute 1.1.2"/>
<item attribute1="attribute 1.2.1" attribute2="attribute 1.2.2" attribute3="attribute 1.2.3"/>
<item attribute1="attribute 1.3.1" attribute2="attribute 1.3.2" attribute3="attribute 1.3.3"/>
</group>
<group name="Group 2">
<item attribute1="attribute 2.1.1" attribute2="attribute 2.1.3" attribute3="attribute 2.1.2"/>
<item attribute1="attribute 2.2.1" attribute2="attribute 2.2.2" attribute3="attribute 2.2.3"/>
<item attribute1="attribute 2.3.1" attribute2="attribute 2.3.2" attribute3="attribute 2.3.3"/>
</group>
</groups>
Итак, я хочу получить все записи об элементах (элементы TR) и добавить их в группу. Это в основном сводится к выбору всех следующих TR элементов, пока мы не встретим элемент, у которого элемент TH является дочерним. Если бы я мог только определить позицию этого первого TR с дочерним элементом TH, указав новый заголовок для группы, это можно было бы сделать с помощью:
<xsl:for-each select="tbody/tr">
<xsl:if test="th">
<xsl:element name="group">
<xsl:attribute name="name"><xsl:value-of select="th"/></xsl:attribute>
<xsl:for-each select="following-sibling::tr[position() < $positionOfNextThElement]">
<xsl:call-template name="item"/>
</xsl:for-each>
</xsl:element>
</xsl:if>
</xsl:for-each>
Однако я не могу определить положение первого обнаруженного тега TR / TH.
Как уже говорилось, я пытался работать с рекурсией в шаблонах: всегда вызывать шаблон "item" и в этом шаблоне определить, хотим ли мы также вызывать его для следующего элемента. Я думаю, что проблема заключается в вызове шаблона изнутри шаблона. Элемент в контексте не увеличивается? Должен ли я передать параметр, чтобы определить, над каким элементом мы работаем?
Во всяком случае, это было то, что я придумал:
<xsl:for-each select="tbody/tr">
<xsl:if test="th">
<xsl:element name="group">
<xsl:attribute name="name"><xsl:value-of select="th"/></xsl:attribute>
<xsl:call-template name="item"/>
</xsl:element>
</xsl:if>
</xsl:for-each>
<xsl:template name="item">
<xsl:element name="item">
<xsl:attribute name="attribute1"><xsl:value-of select="following-sibling::tr[1]/td[1]"/></xsl:attribute>
<xsl:attribute name="attribute2"><xsl:value-of select="following-sibling::tr[1]/td[2]"/></xsl:attribute>
<xsl:attribute name="attribute2"><xsl:value-of select="following-sibling::tr[1]/td[3]"/></xsl:attribute>
</xsl:element>
<!-- When the next element has not got a TH tag, continue with invoking this template -->
<xsl:if test="count(following-sibling::tr[1]/th) != 1">
<xsl:call-template name="item"/>
</xsl:if>
</xsl:template>
Любые предложения о том, как это реализовать, приветствуются!