highlightall
highlightall

Reputation: 109

xslt select grandparent node depending on an attribute value of its grandchild node

I'm trying to add different tags to a node depending on an attribute value of its grandchild node.

Sample Input (a 1x3 table):

<table>
    <row>
        <cell row="1" column="1" >heading text one</cell>
    </row>

    <row>
        <cell row="2" column="1" >body text one</cell>
    </row>
    <row>
        <cell row="3" column="1" >body text two</cell>
    </row>
</table>

Need output like this:

<TableElmt>
    <HeadingElmt>
        <RowElmt>
            <CellElmt>heading text one</CellElmt>
        </RowElmt>
    </HeadingElmt>

    <BodyElmt>
        <RowElmt>
            <CellElmt>body text one</CellElmt>
        </RowElmt>
        <RowElmt>
            <CellElmt>body text two</CellElmt>
        </RowElmt>
    </BodyElmt>
</TableElmt>

Basically I can only decide if the row is a heading row based on the @row element of the cell.

Here's what I've tried:

<xsl:template name="matcheverything" match="table">
    <xsl:apply-templates select="row" />
</xsl:template>

<xsl:template name="matchheadings" match="table[*/*/@row=1]">
    <BodyElmt>
        <xsl:apply-templates select="row" />
    </BodyElmt>
</xsl:template>

<xsl:template match="row">
    <xsl:choose>
        <xsl:when test="*/@row=1">
            <HeadingElmt><RowElmt>
                <xsl:apply-templates select="cell"/>
            </RowElmt></HeadingElmt>
        </xsl:when>
        <xsl:otherwise>
            <RowElmt>
                <xsl:apply-templates select="cell"/>
            </RowElmt>
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>

<xsl:template match="cell">
    <CellElmt><xsl:apply-templates select="*"/></CellElmt>
</xsl:template>

I was thinking the "matchheadings" template, having a more specific match requirement, should recognize the heading row, however it's actually matching every single row in the table.

So my actual out put from this stylesheet is every row treated as a heading row - very bad :(

<TableElmt>
    <HeadingElmt>
        <RowElmt>
            <CellElmt>heading text one</CellElmt>
        </RowElmt>

        <RowElmt>
            <CellElmt>body text one</CellElmt>
        </RowElmt>
        <RowElmt>
            <CellElmt>body text two</CellElmt>
        </RowElmt>
    </HeadingElmt>
</TableElmt>

Upvotes: 1

Views: 2284

Answers (2)

user357812
user357812

Reputation:

Edit: It looks like I missed this

Basically I can only decide if the row is a heading row based on the @row element of the cell.

This stylesheet:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="table">
        <TableElmt>
            <HeadingElmt>
                <xsl:apply-templates select="row[cell/@row=1]"/>
            </HeadingElmt>
            <BodyElmt>
                <xsl:apply-templates select="row[cell/@row!=1]"/>
            </BodyElmt>
        </TableElmt>
    </xsl:template>
    <xsl:template match="row">
        <RowElmt>
            <xsl:apply-templates/>
        </RowElmt>
    </xsl:template>
    <xsl:template match="cell">
        <CellElmt>
            <xsl:apply-templates/>
        </CellElmt>
    </xsl:template>
</xsl:stylesheet>

Output:

<TableElmt>
    <HeadingElmt>
        <RowElmt>
            <CellElmt>heading text one</CellElmt>
        </RowElmt>
    </HeadingElmt>
    <BodyElmt>
        <RowElmt>
            <CellElmt>body text one</CellElmt>
        </RowElmt>
        <RowElmt>
            <CellElmt>body text two</CellElmt>
        </RowElmt>
    </BodyElmt>
</TableElmt>

Upvotes: 1

Dimitre Novatchev
Dimitre Novatchev

Reputation: 243529

This transformation:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:template match="table">
  <TableElmt>
   <xsl:apply-templates/>
  </TableElmt>
 </xsl:template>

 <xsl:template match="row[cell/@row='1']">
  <HeadingElmt>
   <xsl:apply-templates select="." mode="copy"/>
  </HeadingElmt>
 </xsl:template>

 <xsl:template match="row[cell[not(@row='1')]][1]">
  <BodyElmt>
   <xsl:apply-templates select=".|following-sibling::row" mode="copy"/>
  </BodyElmt>
 </xsl:template>

 <xsl:template match="row" mode="copy">
   <RowElmt>
     <xsl:apply-templates/>
   </RowElmt>
 </xsl:template>

 <xsl:template match="cell">
   <CellElmt>
    <xsl:value-of select="."/>
   </CellElmt>
 </xsl:template>

 <xsl:template match="row"/>
</xsl:stylesheet>

when applied on the provided XML document:

<table>
    <row>
        <cell row="1" column="1" >heading text one</cell>
    </row>
    <row>
        <cell row="2" column="1" >body text one</cell>
    </row>
    <row>
        <cell row="3" column="1" >body text two</cell>
    </row>
</table>

produces the wanted, correct result:

<TableElmt>
    <HeadingElmt>
        <RowElmt>
            <CellElmt>heading text one</CellElmt>
        </RowElmt>
    </HeadingElmt>
    <BodyElmt>
        <RowElmt>
            <CellElmt>body text one</CellElmt>
        </RowElmt>
        <RowElmt>
            <CellElmt>body text two</CellElmt>
        </RowElmt>
    </BodyElmt>
</TableElmt>

Upvotes: 1

Related Questions