この質問と同様に (関連するエントリは他にもありますが、新しいユーザーとして投稿できる URL は 1 つだけです): Xpath Get elements that are between 2 elements
「その他/区切り」要素間で発生する一連の要素の選択に関して質問があります。この状況は、XSLT を使用してフラットな HTML テーブルを階層的な XML 構造に変換しようとしたときに発生します。テンプレートで再帰を使用しようとしましたが、おそらく私のせいでデッドロックが発生したため、saxon はこれを受け入れることを拒否しましたが、最初から始めましょう。
最初のソース データは 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 要素) を取得し、それらをグループに追加したいと考えています。これは基本的に、子として TH 要素を持つ要素に遭遇するまで、後続の兄弟 TR 要素をすべて選択することになります。TH 子を持つこの最初の TR の位置のみを特定でき、グループの新しい見出しを示すことができる場合、これは次のように行うことができます。
<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 タグの位置を特定できません。
前述のように、テンプレートで再帰を使用してみました。常に「アイテム」テンプレートを呼び出し、このテンプレートで次のアイテムでもそれを呼び出すかどうかを決定します。問題は、テンプレート内からのテンプレートの呼び出しにあると思います。コンテクスト内のアイテムが増えない?どの項目に取り組んでいるかを判断するためにパラメーターを渡す必要がありますか?
とにかく、これは私が思いついたものでした:
<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>
これを実現する方法についての提案は大歓迎です!