Turn a list into table

13 October 2012

Keywords: dom, transformation, list, table

The question is to transform a definition list output by upm_date_menu plugin into table like this seen on the bottom of this page. Here is the source of upm_date_menu output (shamelessly borrowed from mistersugar.com/archive, sorry), that we save in some variable, say “archive”:

<txp:variable name="archive">
<dl>
<dt>2012</dt>
	<dd><a href="http://mistersugar.com/article/2012-01">Jan</a></dd>
	<dd><a href="http://mistersugar.com/article/2012-02">Feb</a></dd>
	...
<dt>2011</dt>
	<dd><a href="http://mistersugar.com/article/2011-01">Jan</a></dd>
	...
</dl>
</txp:variable>

Our aim is to transform dt into th and dd into td, then display them in the “horizontal” order:

<txp:etc_query data='<txp:variable name="archive" />'
  query="dl" parse="before" wraptag="table">
	<thead><tr>{dt&=<th>{node()}</th>}</tr></thead>
	<txp:etc_query data="[1..12]" wraptag="tbody" break="tr">
		{{dt/following-sibling::dd[{?}]&=<td>{{node()}}</td>}}
	</txp:etc_query>
</txp:etc_query>

The internal etc_query is there to generate twelve table row templates, one for each month. Once preparsed (hence parse="before"), it will produce

<tbody>
	<tr>{dt/following-sibling::dd[1]&=<td>{node()}</td>}</tr>
	...
	<tr>{dt/following-sibling::dd[12]&=<td>{node()}</td>}</tr>
</tbody>

inside the external etc_query. We could safely replace it with this block, but it nicely illustrates the nesting syntax of etc_query.

Finally, the instruction {dt&=<th>{node()}</th>} will put the content of each dt inside a <th>...</th> tag, and {dt/following-sibling::dd[1]&=<td>{node()}</td>} will match every first dd following some dt, i.e. all January links, and put its content inside <td>...</td>. The second row regroups all February links, and so on. And here is the result:

201220112010200920082007200620052004200320022001200019991994
JanJanJanJanJanJanJanJanJanJanJanJanJanJanJan
FebFebFebFebFebFebFebFebFebFebFebFebFebFebFeb
MarMarMarMarMarMarMarMarMarMarMarMarMarMarMar
AprAprAprAprAprAprAprAprAprAprAprAprAprAprApr
MayMayMayMayMayMayMayMayMayMayMayMayMayMayMay
JunJunJunJunJunJunJunJunJunJunJunJunJunJunJun
JulJulJulJulJulJulJulJulJulJulJulJulJulJulJul
AugAugAugAugAugAugAugAugAugAugAugAugAugAugAug
SepSepSepSepSepSepSepSepSepSepSepSepSepSepSep
OctOctOctOctOctOctOctOctOctOctOctOctOctOctOct
NovNovNovNovNovNovNovNovNovNovNovNovNovNovNov
DecDecDecDecDecDecDecDecDecDecDecDecDecDecDec

If you have many articles, you may consider wrapping the output of both upm_date_archive and etc_query into etc_cache for better performance.

An even better option will be to use CSS2 display:table(-row|-cell) properties, rather than node transformation:

<txp:etc_query data='<txp:variable name="archive" />'
  query="dl" parse="before" wraptag="dl">
	<div>{dt}</div>
	<txp:etc_query data="[1..12]">
		<div>{{dt/following-sibling::dd[{?}]}}</div>
	</txp:etc_query>
</txp:etc_query>

<style>
	dl{display:table}
	dl>div{display:table-row}
	dt,dd{display:table-cell}
</style>

File(s)