Wednesday, April 22, 2009

Coldfusion writing simple xslt

I think it would be kinda cool to not have to write xslt as much any more, so a coworker and I created some helper functions to handle tables for us. So instead of writing xslt to create a table tag where we can pump xml into we created coldfusion functions with which can shoot args and write the xslt for us.

Here we call a beginTable() with which we can give it attributes.

<cffunction name="beginTable" access="public" returntype="string" output="false" >

<cfset var local = {} />

<cfset arguments = getArguments(arguments) />

<cfsavecontent variable="local.string">
<cfoutput>
<xsl:call-template name="beginTable">

#renderXSLTParams(argumentCollection=arguments)#

</xsl:call-template>
</cfoutput>
</cfsavecontent>

<cfreturn local.string>

</cffunction>

First we can getArguments which handles our common attributes of the tag we are trying to create. getArguments() can be used to set out defaults but of simplicity we just loop a list of common attributes.

<cffunction name="getArguments" access="public" output="false" returntype="struct">
<cfargument name="args" required="true" />

<cfset var local = {} />

<cfset local.args = arguments.args />

<cfloop list="class,style,title,alt,id,height,width,colspan,cellspacing,cellpadding,align,border,src,value" index="local.i">
<cfset local.args[lcase(local.i)] = getKey(lcase(local.i),local.args,"#local.i#") />
</cfloop>

<cfreturn local.args />

</cffunction>

Second, we write the xlst beginTable template and create the xslt params using renderXSLTParams.

<cffunction name="renderXSLTParams" access="public" returntype="string" output="false" >

<cfset var local = {} />
<cfset var i = "" />

<cfsavecontent variable="local.string">
<cfoutput>
<cfloop collection="#arguments#" item="i">
<xsl:with-param name="#lcase(i)#">
<cfif (FindNoCase('%',arguments[i],1) or FindNoCase('px',arguments[i],1) )>
<xsl:text>#arguments[i]#
<cfelse>
<xsl:value-of select="#lcase(arguments[i])#"/>
</cfif>
</xsl:with-param>
</cfloop>
</cfoutput>
</cfsavecontent>

<cfreturn local.string/>

</cffunction>

That takes care of creating the xslt snippet for the begin table tag, now we have to load the tag at the bottom of the xslt so we can call the template and invoke the params. To do this we output the load function which contains all our template snippets.

<cffunction name="load" access="public" output="false" returntype="string" >

<cfset var local = {}/>

<cfsavecontent variable="local.string">
<cfoutput>
<xsl:template name="beginTable">
#getTemplateParams()#
<xsl:text disable-output-escaping="yes"><</xsl:text>table
#getXSLTParams()#
<xsl:text disable-output-escaping="yes">></xsl:text>
</xsl:template>

<xsl:template name="endTable">
<xsl:text disable-output-escaping="yes"><</xsl:text>/table
</xsl:template>

</cfoutput>
</cfsavecontent>

<cfreturn local.string/>

</cffunction>

In the load function we call getTemplateParams() to create our template params.


<cffunction name="getTemplateParams" access="public" returntype="string" output="false" >

<cfset var local = {}/>
<cfset var i = ""/>

<cfset arguments = getArguments(arguments)/>

<cfsavecontent variable="local.string">
<cfoutput>

<cfloop collection="#arguments#" item="i">

<xsl:param name="#lcase(i)#"/>

</cfloop>

</cfoutput>

</cfsavecontent>

<cfreturn local.string/>

</cffunction>

Next we call getXSLTParams(). to actually invoke the xslt params

<cffunction name="getXSLTParams" access="public" returntype="string" output="false" >

<cfset var local = {}/>
<cfset var i = ""/>

<cfset arguments = getArguments(arguments)/>

<cfsavecontent variable="local.string">
<cfoutput>

<cfloop collection="#arguments#" item="i">
<xsl:if test="$#lcase(i)# != '' ">
#lcase(i)# ='
</xsl:if>
</cfloop>

</cfoutput>
</cfsavecontent>

<cfreturn local.string/>

</cffunction>

And that should do it.

Thursday, April 9, 2009

Accessing a queries row by row number

query.column[rownumber]

I was asked to do a task which involved a select box with arrows on each side of it. The arrows were to be used for the next and previous record in the select box when the page first rendered. For awhile I have wanted to use a query row number to access data directly and now get the chance to.

I used the current selected id and loop the query just got the above and below row from the current row by accessing the query struct.

Example:


<cfset the_id="124"/>
<cfset above_id=""/>
<cfset below_id=""/>

<cfloop query="the_query">

<cfif the_id = the_query.id>

<cfset above_id= the_query.id[currentrow + 1] />

<cfset below_id= the_query.id[currentrow - 1] />
<cfbreak />
</cfif>
</cfloop>