Comme similaire à cette question (il y a des entrées plus liées, mais en tant que nouvel utilisateur, je ne peux poster une URL): Xpath Get elements that are between 2 elementsXPath dans XSLT: sélectionner des éléments qui sont entre 2 autres éléments, partie II
I avoir une question concernant la sélection de l'ensemble des éléments qui se produisent entre les éléments «autres/délimiteurs». Cette situation se produit lorsque vous tentez de transformer une table HTML plate en une structure XML hiérarchique à l'aide de XSLT. J'ai essayé d'utiliser la récursivité dans les gabarits, mais saxon a refusé d'accepter cela car il en résultait un blocage, probablement de ma faute, mais commençons par le début.
D'abord les données source est la table 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>
La sortie ciblée en XML serait:
<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>
Je veux avoir toutes les entrées de poste, (éléments TR) et ajoutez-les à un groupe. Cela revient essentiellement à sélectionner tous les éléments TR suivants-frères jusqu'à ce que nous en rencontrions un qui a un élément TH en tant qu'enfant. Si je ne pouvais déterminer la position de ce premier TR qui a un enfant TH, ce qui indique une nouvelle rubrique pour un groupe, cela pourrait se faire avec:
<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>
Cependant, je ne suis pas en mesure de déterminer la position du première fois rencontré tag TR/TH. Comme je l'ai dit, j'ai essayé de travailler avec la récursivité dans les templates: appelez toujours le template "item" et dans ce template, déterminez si nous voulons l'invoquer sur le prochain item. Je pense que le problème est dans l'invocation du modèle à partir du modèle. L'élément en contexte n'augmente pas? Dois-je remettre un paramètre pour déterminer sur quel article nous travaillons?
Quoi qu'il en soit, ce fut ce que je suis venu avec:
<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>
Toutes les suggestions sur la façon de réaliser ce sont les bienvenus!
Pouces pour votre réponse! Cela a fait l'affaire, heureusement le nombre d'attributs est statique. Je vais vérifier la documentation référencée pour les futurs problèmes de regroupement. – Holtkamp