xslt - XSL key to get elements that meet specific criteria -
i working table entry elements , want preceding entry elements in same table pass following test:
parent::row/preceding-sibling::row/entry [@morerows >= count(parent::row/following-sibling::row [not(preceding-sibling::row/entry [generate-id() = $id])])] [count(preceding-sibling::entry [not(@morerows)]) + 1 = count(current()/preceding-sibling::entry) + 1]
the xpath gives me desired result, painfully slow..... use key having problems.
i defined key follows:
<xsl:key name="morerowsentry" match="entry[@morerows]" use="."/>
while key retrieve entry elements morerows attribute, need retrieve within same ancestor table. well, @ loss how test morerows value. have tried things such :
<xsl:for-each select="key('morerowsentry', (@morerows >= count(parent::row/following-sibling::row[not(preceding-sibling::row/entry[generate-id() = $id])])) , (count(preceding-sibling::entry[not(@morerows)]) + 1 = count(current()/preceding-sibling::entry) + 1))">
i have using xsl 1.0. , appreciated.
some further information:
i converting cals table ooxml. each entry in cals table within row in know there cells missing, need add additional cells. these entry elements have $id
generate-id() value of element.
i have xpath above, tests entry elements in preceding rows of table (parent::row/preceding-sibling::row/entry
) have morerows attribute greater or equal number of rows between , entry id of $id
, , in correct position in empty cell should inserted (count(preceding-sibling::entry[not(@morerows)]) + 1 = count(current()/preceding-sibling::entry) + 1
)
simplified sample input:
<table> <tbody> <row> <entry morerows="2">a</entry> <entry morerows="1">b</entry> <entry>c</entry> <entry>d</entry> </row> <row> <entry>e</entry> <entry>f</entry> </row> <row> <entry>g</entry> <entry>h</entry> <entry>i</entry> </row> <row> <entry>j</entry> <entry>k</entry> <entry>l</entry> <entry>m</entry> </row> </tbody> </table>
simplified sample output:
<w:tbl> <w:tr> <w:tc> <w:p> <w:r> <w:t>a</w:t> </w:r> </w:p> </w:tc> <w:tc> <w:p> <w:r> <w:t>b</w:t> </w:r> </w:p> </w:tc> <w:tc> <w:p> <w:r> <w:t>c</w:t> </w:r> </w:p> </w:tc> <w:tc> <w:p> <w:r> <w:t>d</w:t> </w:r> </w:p> </w:tc> </w:tr> <w:tr> <w:tc> <w:tcpr> <w:vmerge/> </w:tcpr> <w:p/> </w:tc> <w:tc> <w:tcpr> <w:vmerge/> </w:tcpr> <w:p/> </w:tc> <w:tc> <w:p> <w:r> <w:t>e</w:t> </w:r> </w:p> </w:tc> <w:tc> <w:p> <w:r> <w:t>f</w:t> </w:r> </w:p> </w:tc> </w:tr> <w:tr> <w:tc> <w:tcpr> <w:vmerge/> </w:tcpr> <w:p/> </w:tc> <w:tc> <w:p> <w:r> <w:t>g</w:t> </w:r> </w:p> </w:tc> <w:tc> <w:p> <w:r> <w:t>h</w:t> </w:r> </w:p> </w:tc> <w:tc> <w:p> <w:r> <w:t>i</w:t> </w:r> </w:p> </w:tc> </w:tr> <w:tr> <w:tc> <w:p> <w:r> <w:t>j</w:t> </w:r> </w:p> </w:tc> <w:tc> <w:p> <w:r> <w:t>k</w:t> </w:r> </w:p> </w:tc> <w:tc> <w:p> <w:r> <w:t>l</w:t> </w:r> </w:p> </w:tc> <w:tc> <w:p> <w:r> <w:t>m</w:t> </w:r> </w:p> </w:tc> </w:tr> </w:tbl>
the input uses morerows attribute specify spanned rows. output requires actual cells inserted <w:vmerge/>
element each spanned cell.
another sample:
in sample, there merged columns (specified namest , nameend attributes) must taken in account:
<table> <tgroup cols="7"> <colspec colname="col1"/> <colspec colname="col2"/> <colspec colname="col3"/> <colspec colname="col4"/> <colspec colname="col5"/> <colspec colname="col6"/> <colspec colname="col7"/> <tbody> <row> <entry morerows="5">a</entry> <entry morerows="1">b</entry> <entry morerows="1">c</entry> <entry>d</entry> <entry>e</entry> <entry>f</entry> <entry>g</entry> </row> <row> <entry>2d</entry> <entry>2e</entry> <entry>2f</entry> <entry>2g</entry> </row> <row> <entry morerows="1">3b</entry> <entry morerows="1">3c</entry> <entry>3d</entry> <entry>3e</entry> <entry>3f</entry> <entry>3g</entry> </row> <row> <entry>4d</entry> <entry>4e</entry> <entry>4f</entry> <entry>4g</entry> </row> <row> <entry morerows="1" nameend="col6" namest="col2">3g - 4g</entry> <entry morerows="1">5g</entry> </row> </tbody> </tgroup> </table>
output:
<w:tbl> <w:tr> <w:tc> <w:tcpr> <w:vmerge w:val="restart"/> </w:tcpr> <w:p> <w:r> <w:t>a</w:t> </w:r> </w:p> </w:tc> <w:tc> <w:tcpr> <w:vmerge w:val="restart"/> </w:tcpr> <w:p> <w:r> <w:t>b</w:t> </w:r> </w:p> </w:tc> <w:tc> <w:tcpr> <w:vmerge w:val="restart"/> </w:tcpr> <w:p> <w:r> <w:t>c</w:t> </w:r> </w:p> </w:tc> <w:tc> <w:p> <w:r> <w:t>d</w:t> </w:r> </w:p> </w:tc> <w:tc> <w:p> <w:r> <w:t>e</w:t> </w:r> </w:p> </w:tc> <w:tc> <w:p> <w:r> <w:t>f</w:t> </w:r> </w:p> </w:tc> <w:tc> <w:p> <w:r> <w:t>g</w:t> </w:r> </w:p> </w:tc> </w:tr> <w:tr> <w:tc> <w:tcpr> <w:vmerge/> </w:tcpr> <w:p/> </w:tc> <w:tc> <w:tcpr> <w:vmerge/> </w:tcpr> <w:p/> </w:tc> <w:tc> <w:tcpr> <w:vmerge/> </w:tcpr> <w:p/> </w:tc> <w:tc> <w:p> <w:r> <w:t>2d</w:t> </w:r> </w:p> </w:tc> <w:tc> <w:p> <w:r> <w:t>2e</w:t> </w:r> </w:p> </w:tc> <w:tc> <w:p> <w:r> <w:t>2f</w:t> </w:r> </w:p> </w:tc> <w:tc> <w:p> <w:r> <w:t>2g</w:t> </w:r> </w:p> </w:tc> </w:tr> <w:tr> <w:tc> <w:tcpr> <w:vmerge/> </w:tcpr> <w:p/> </w:tc> <w:tc> <w:tcpr> <w:vmerge w:val="restart"/> </w:tcpr> <w:p> <w:r> <w:t>3b</w:t> </w:r> </w:p> </w:tc> <w:tc> <w:tcpr> <w:vmerge w:val="restart"/> </w:tcpr> <w:p> <w:r> <w:t>3c</w:t> </w:r> </w:p> </w:tc> <w:tc> <w:p> <w:r> <w:t>3d</w:t> </w:r> </w:p> </w:tc> <w:tc> <w:p> <w:r> <w:t>3e</w:t> </w:r> </w:p> </w:tc> <w:tc> <w:p> <w:r> <w:t>3f</w:t> </w:r> </w:p> </w:tc> <w:tc> <w:p> <w:r> <w:t>3g</w:t> </w:r> </w:p> </w:tc> </w:tr> <w:tr> <w:tc> <w:tcpr> <w:vmerge/> </w:tcpr> <w:p/> </w:tc> <w:tc> <w:tcpr> <w:vmerge/> </w:tcpr> <w:p/> </w:tc> <w:tc> <w:tcpr> <w:vmerge/> </w:tcpr> <w:p/> </w:tc> <w:tc> <w:p> <w:r> <w:t>4d</w:t> </w:r> </w:p> </w:tc> <w:tc> <w:p> <w:r> <w:t>4e</w:t> </w:r> </w:p> </w:tc> <w:tc> <w:p> <w:r> <w:t>4f</w:t> </w:r> </w:p> </w:tc> <w:tc> <w:p> <w:r> <w:t>4g</w:t> </w:r> </w:p> </w:tc> </w:tr> <w:tr> <w:tc> <w:tcpr> <w:vmerge/> </w:tcpr> <w:p/> </w:tc> <w:tc> <w:tcpr> <w:gridspan w:val="5"/> </w:tcpr> <w:p> <w:r> <w:t>3g - 4g</w:t> </w:r> </w:p> </w:tc> <w:tc> <w:p> <w:r> <w:t>5g</w:t> </w:r> </w:p> </w:tc> </w:tr> </w:tbl>
if processor can the exslt:node-set
function or equivalent such that provided msxml attack procedurally, using tail-recursive template. ugly, know, , against recommend xslt, in case think way efficiently pass information 1 row next. assuming first row of table have entry
every column, how this:
<xsl:template match="tbody"> <w:tbl> <xsl:apply-templates select="row[1]"> <xsl:with-param name="rowspec"> <!-- build row info structure assuming first row has right number of entry elements. nothing spans first row, @span=0 --> <xsl:for-each select="row[1]/entry"> <r span="0" /> </xsl:for-each> </xsl:with-param> </xsl:apply-templates> </w:tbl> </xsl:template> <xsl:template match="row"> <xsl:param name="rowspec" /> <xsl:variable name="therow" select="." /> <w:tr> <!-- build output row --> <xsl:for-each select="exsl:node-set($rowspec)/r"> <w:tc> <xsl:choose> <xsl:when test="@span = 0"> <!-- row has entry column --> <xsl:apply-templates select="$therow/entry[ count(current()/preceding-sibling::r[@span = 0]) + 1]" /> </xsl:when> <xsl:otherwise> <!-- column spans previous row --> <w:tcpr> <w:vmerge/> </w:tcpr> <w:p/> </xsl:otherwise> </xsl:choose> </w:tc> </xsl:for-each> </w:tr> <!-- process next row recalculated spans --> <xsl:apply-templates select="following-sibling::row[1]"> <xsl:with-param name="rowspec"> <xsl:for-each select="exsl:node-set($rowspec)/r"> <xsl:choose> <xsl:when test="@span = 0"> <!-- had entry element column, use @morerows next span, or 0 if doesn't have 1 --> <xsl:choose> <xsl:when test="$therow/entry[ count(current()/preceding-sibling::r[@span = 0]) + 1]/@morerows"> <r span="{$therow/entry[ count(current()/preceding-sibling::r[@span = 0]) + 1]/@morerows}" /> </xsl:when> <xsl:otherwise> <r span="0" /> </xsl:otherwise> </xsl:choose> </xsl:when> <xsl:otherwise> <!-- didn't have entry column, span previous row - subtract 1 span when pass on next row --> <r span="{@span - 1}" /> </xsl:otherwise> </xsl:choose> </xsl:for-each> </xsl:with-param> </xsl:apply-templates> </xsl:template> <xsl:template match="entry"> <w:p> <w:r> <w:t><xsl:value-of select="." /></w:t> </w:r> </w:p> </xsl:template>
(wow, ended more complex expected when started it, i've tested out , seems work correctly). idea here build structure encodes number of rows each column still needs span on @ point row processed. first row we'll have
<r span="0"/> <r span="0"/> <r span="0"/> <r span="0"/>
then second it'll be
<r span="2"/> <r span="1"/> <r span="0"/> <r span="0"/>
the third
<r span="1"/> <r span="0"/> <r span="0"/> <r span="0"/>
etc. each row iterate on this structure rather on entry
elements themselves.
edit: you've changed question need account possibility of column spans row spans gets much messier. since we're committed using node-set function, think two-step approach hinted @ larsh, first expand out column spanning entries real entry
elements (with attribute identify them such) , process expanded version of xml in place of original.
Comments
Post a Comment