views:

713

answers:

4

How can one call a ColdFusion function, passing in attribute values as arguments, inside an XML transform template statement. For example, something like:

<xsl:template match="date">
    <cfoutput>#DateFormat(now(), <xsl:value-of select="@format"/>)#</cfoutput>
</xsl:template>

Such that the following XML:

<date format="mm/dd/yy" />

Would be matched and transformed to the result of DateFormat(now(), "mm/dd/yy")? Is it possible? I am able to do it with static arguments to DateFormat(), cannot figure out how to extract a value from an attribute/node and use it as an argument. Thank you!

Update

Full version of current attempt:

<cfxml variable="xmlData">
    <?xml version="1.0"?>
    <date format="mm/dd/yy" />
</cfxml>

<cfxml variable="stylesheet">
    <?xml version="1.0"?>
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"&gt;
    <xsl:template match="date">
 <cfoutput>#DateFormat(now(), '<xsl:value-of select="@format"/>')#</cfoutput>
    </xsl:template>
    </xsl:stylesheet>
</cfxml>

<cfoutput>#XmlTransform(xmlData, trim(stylesheet))#</cfoutput>

which results in the following error:

    An error occured while Parsing an XML document.

    Element type "x2l:value-of" must be followed by
    either attribute specifications, ">" or "/>".
A: 

Looks like you just need quotes around the value.

<xsl:template match="date">
    <cfoutput>#DateFormat(now(), '<xsl:value-of select="@format"/>')#</cfoutput>
</xsl:template>

Here's a complete stylesheet, which I tested with an online parser.

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"&gt;

<xsl:template match="date">
    <cfoutput>#DateFormat(now(), '<xsl:value-of select="@format"/>')#</cfoutput>
</xsl:template>

</xsl:stylesheet>

And here's the XML code I used to test:

<?xml version="1.0"?>
<date format="mm/dd/yy" />
Patrick McElhaney
adding quotes results in the following: javax.xml.transform.TransformerConfigurationException: javax.xml.transform.TransformerException: org.xml.sax.SAXParseException: Element type "x36l:value-of" must be followed by either attribute specifications, ">" or "/>".
Tacomanator
Thanks Patrick. It works fine in the w3schools parser to generate valid CFML, but then the question is how do I have that CFML evaluated during the transform. If I try to use the code in ColdFusion, I get a "Missing argument name." error. I thought maybe it was because the <cfouptut> was being evaluated before the @format value was available, but this does not make sense as DateFormat(now(), '') should not cause an error..
Tacomanator
I updated the original question with a full version of the code for clarification
Tacomanator
+2  A: 

You can use CFML to generate an XSL template.

You can also use an XSL template to turn appropriate XML into CFML (as in Patrick's answer).

However, these are two distinct operations, and cannot happen together at the same time (if you need both actions, you must do one then the other).

Peter Boughton
I see, yes that is what I was trying to do. So it sounds like what I want instead is to generate CFML from the XML and then evaluate it?
Tacomanator
To elaborate a little bit on Peter's answer above: Think about it sort of like mixing JavaScript and CFML -- they aren't both evaluated at the same time, so you can't just use a JavaScript variable in a ColdFusion function, or vice-versa. One is evaluated, and then the other, and there is no back-and-forth.
Adam Tuttle
Thank you, I understand now. I think I will create a parser to handle this instead then.
Tacomanator
A: 

Why don't you use exslt datetime?

http://exslt.org/date/functions/format-date/index.html

Xalan supports it, possibly others, too.

alamar
Thanks alamar I did consider that, but date is just one example of a transformation that I would like to perform. Some others don't have equivalent library functions.
Tacomanator
+1  A: 

Okay, here's what I think you're trying to do. You can't parse with XSLT and ColdFusion in one pass. You have to make two passes.

<cfxml variable="xmlData">
    <?xml version="1.0"?>
    <date format="mm/dd/yy" />
</cfxml>

<cfxml variable="stylesheet">

    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"&gt;

    <xsl:template match="date">
        #DateFormat(now(), "<xsl:value-of select="@format"/>")#
    </xsl:template>   

    </xsl:stylesheet>  

</cfxml>


<cfset filename = "#createUUID()#.cfm" />
<cffile action="write" file="#getDirectoryFromPath(getCurrentTemplatePath())##filename#" output="<cfoutput>#XmlTransform(xmlData, trim(stylesheet))#</cfoutput>"/>

<cfinclude template="#filename#"/>
Patrick McElhaney
but if I escape the #'s, the function will not be evaluated, and the result of XmlTransform(xmlData, trim(stylesheet)) will just be "#DateFormat(now(), 'mm/dd/yy')#" rather than the value of #DateFormat(now(), 'mm/dd/yy')#
Tacomanator
Rewrote the answer based on your feedback.
Patrick McElhaney
this is not really looking pretty, but thanks for showing how it could be accomplished :) I think I'm going to work on a parser based approach instead...
Tacomanator