The i-Technology Media!
Register | Log in
   
 
.NET  ·  AJAX  ·  CLOUD  ·  ECLIPSE  ·  FLEX  ·  OPEN WEB  ·  iPHONE  ·  JAVA  ·  LINUX  ·  OPEN SOURCE  ·  ORACLE  ·  PBDJ  ·  SEARCH  ·  SILVERLIGHT  ·  SOA  ·  VIRTUALIZATION  ·  WEB 2.0  ·  WIRELESS  ·  XML
Comments
Plone and Drupal: Different Approaches, Different Results
paul.nowak wrote: Matt, thanks for the comments. I made an error on the version of Plone. It's 2.5 Plone running on Zope 2.9x. In regards to the additional products, we have a skin installed and we have a product that we had custom developed for us that connects to a PostgreSQL database. We've looked at slow PostgreSQL queries causing problems and have not been able to find an issue. We've also tested for the case where the PostgreSQL server is down and have not been able to create an issue. We therefor...
Nov. 4, 2009 04:19 PM EST
Cloud Expo on Google News
Did you read today's front page stories & breaking news?


2009 East
PLATINUM SPONSORS:
IBM
Smarter Business Solutions Through Dynamic Infrastructure
IBM
Smarter Insights: How the CIO Becomes a Hero Again
Microsoft
Windows Azure
GOLD SPONSORS:
Appsense
Why VDI?
CA
Maximizing the Business Value of Virtualization in Enterprise and Cloud Computing Environments
ExactTarget
Messaging in the Cloud - Email, SMS and Voice
Freedom OSS
Stairway to the Cloud
Sun
Sun's Incubation Platform: Helping Startups Serve the Enterprise
POWER PANELS:
Cloud Computing & Enterprise IT: Cost & Operational Benefits
How and Why is a Flexible IT Infrastructure the Key To the Future?
Click For 2008 West
Event Webcasts

2009 East
GOLD SPONSORS:
CA
Get Your Transactions Under Control: SOA Performance Management
Software AG
Performance Driven Adoption: The Secret to Advancing SOA
Intel
The Evolving SOA Appliance: 3 Game-Changing Innovations
SILVER SPONSOR:
Denodo
Data Mashups: Deliver Your Project Faster with Virtualized Data Services Across Internal & External Sources
POWER PANELS:
The Business Value of Service Orientation
Driving Profitability Through User Experience
Click For 2008 West
Event Webcasts
Live Google News by SYS-CON!
Top Three Links You Must Click On


Custom Tags
Forging Custom Tags
Forging Custom Tags

By: Rob Brooks-Bilson
Sep. 17, 2003 12:00 AM

Why Allaire ColdFusion® is HOT!
No doubt about it -- ColdFusion is HOT! What makes ColdFusion such an attractive development platform for Web applications is the fact that it is completely extensible. Since version 2.0, ColdFusion has allowed developers to extend the platform's capabilities using custom tags created in Microsoft Visual C++. Although a powerful feature, it requires a decent knowledge of C++ as well as Microsoft's Visual C++ compiler - putting it out of consideration for a lot of developers.

Version 3.0 of ColdFusion introduced CFML-based Custom Tags. These Custom Tags are composed entirely of CFML and can be written by anyone with basic experience in writing ColdFusion applications. Custom Tags allow you to do everything from automating repetitive tasks to building complex intelligent agents, using ColdFusion built in tags and functions. They work by having a ColdFusion template pass them any number of parameters to the tag for processing. The tag receives the parameters, processes them as necessary, performs a specified action, and/or returns output to the calling template.

Basic concepts
While building Custom Tags using CFML is relatively simple, there are a number of basic concepts to bear in mind. Your foray into building Custom Tags should begin with a trip to the ColdFusion Users Guide. Although the documentation on building Custom Tags is thin, it does present just enough to get you started. With that said, let's look at one of the most important and often misunderstood elements in Custom Tag building - passing variables and attributes to and from Custom Tags.

Passing values from your ColdFusion template to a Custom Tag is easy. All that is involved is calling a Custom Tag from your ColdFusion template and passing any appropriate values as attributes. You simply markup the tag with the appropriate parameters and away you go. Below is the syntax for calling a Custom Tag from within a ColdFusion template:


<CF_MyTag

     Attribute1="value1"

     Attribute2="value2"

     AttributeN="valueN">

As you can see from the above example, calling the tag involves nothing more than referencing the tag name along with any required or optional attributes. Attribute values can be alphanumeric strings or ColdFusion variables. This allows you to pass both static and dynamic values to your Custom Tags for processing.

Once values have been passed from the ColdFusion template, they are available for processing within the Custom Tag. ColdFusion introduces two new variable scopes for dealing with values passed to custom tags: attributes and caller.

New attribute scope
The attributes scope allows Custom Tags to identify values that have been passed to them for processing. Because the attributes scope uniquely identifies a value passed to a Custom Tag, it must be referred to explicitly within the calling tag. If you leave off the attributes scope, ColdFusion will assume that you are trying to reference a local variable and throw an error (unless a local variable with the same name as the attribute exists). The following example illustrates the concept of assigning the value of a passed attribute to a local variable within a Custom Tag:


<!--- Begin ColdFusion Template 1 --->

<!--- call custom tag --->

<CF_DisplayText

   TextToDisplay="Show this on the screen from within the 
      Custom Tag.">

<!--- Begin ColdFusion Custom  Tag --->

<CFSET LocalTextVariable = attributes.TextToDisplay>

<CFOUTPUT>

#LocalTextVariable#

</CFOUTPUT>

In the above example, all we did was assign the attribute TextToDisplay from the calling ColdFusion template to a local variable inside of the Custom Tag called LocalTextVariable. This gives the advantage of not having to refer to the variable by the attributes scope as well as allowing us to reference the original value of the variable before any processing is applied. This is a technique isn't essential, but I find it useful nonetheless.

The caller scope
Passing variables to ColdFusion Custom Tags is not a one way street. The last example showed how you could output the results of a call to a Custom Tag within the Custom Tag, but what if you want to pass information back to the template that called the tag? Enter the caller variable scope. The caller scope allows you to pass information back to the ColdFusion template that called the Custom Tag. For a better idea of how this works, consider the following modification to our last example in which we pass a text string to a Custom Tag, the Custom Tag converts the string to all uppercase and then passes the converted string back to the calling template:


<!--- Begin ColdFusion Template 1 --->

<!--- call custom tag --->

<CF_DisplayText

   TextToDisplay="Show this on the screen from within the 
      Custom Tag.">

<!--- display results from the custom tag within a CFOUTPUT section, 
   referencing the variable name from the caller scope within the 
   Custom Tag--->

<CFOUTPUT>

Output from Custom Tag:  #ShowText#

</CFOUTPUT>


<!--- Begin ColdFusion Custom  Tag --->

<!--- assign attribute to local variable --->

<CFSET LocalTextVariable = attributes.TextToDisplay>


<!--- convert text string to all uppercase --->

<CFSET UpperCaseText = UCase(LocalTextVariable)>


<!--- pass converted string back to calling template --->

<CFSET Caller.ShowText = UpperCaseText>

As you can see from the simplistic example, all you have to do to return a variable from a Custom Tag is to set the variable equal to an arbitrary variable name with the caller scope. This works great for any scenario where you need to return a single result for any number of variables. The next logical step, then, is to have a Custom Tag return the results of a query to a ColdFusion template. This allows you to write sophisticated Custom Tags that return multiple values for each variable passed. A good example of this is the CF_StockGrabber Custom Tag available from the Allaire Tag Gallery. CF_StockGrabber is a Custom Tag that retrieves stock quotes from Yahoo's quote.yahoo.com site and returns them to the calling ColdFusion template as a query. Rather than break down the entire tag step-by-step, I have chosen to highlight the relevant parts.

StockGrabberLite--the template
The first step is to create a ColdFusion template that calls the tag and subsequently displays the results. This is achieved by creating a ColdFusion template with the following elements:


<!--- Template that calls the CF_StockGrabberLite tag --->

<!--- add yhoo twice because of a bug in CFHTTP --->

<CF_StockGrabberLite

     TickerSymbols="yhoo+yhoo+intc+egrp"

     QueryName="MyQuery">

<TABLE BORDER=1>

    <TR>

        <TH BGCOLOR="#FFCC99">Symbol</TH>

        <TH BGCOLOR="#FFCC99">Price</TH>

        <TH BGCOLOR="#FFCC99">Change</TH>

        <TH BGCOLOR="#FFCC99">Time</TH>

        <TH BGCOLOR="#FFCC99">Date</TH>

        <TH BGCOLOR="#FFCC99">Open</TH>

        <TH BGCOLOR="#FFCC99">High</TH>

        <TH BGCOLOR="#FFCC99">Low</TH>

        <TH BGCOLOR="#FFCC99">Volume</TH>

    </TR>

    <CFOUTPUT QUERY="MyQuery">

    <TR>

        <TD BGCOLOR="##EFD6C6">#Symbol#</TD>

        <TD BGCOLOR="##EFD6C6">#Last_Traded_Price#</TD>

        <TD BGCOLOR="##EFD6C6">#Change#</TD>

        <TD BGCOLOR="##EFD6C6">#Last_Traded_Time#</TD>

        <TD BGCOLOR="##EFD6C6">#Last_Traded_Date#</TD>

        <TD BGCOLOR="##EFD6C6">#Opening_Price#</TD>

        <TD BGCOLOR="##EFD6C6">#Days_High#</TD>

        <TD BGCOLOR="##EFD6C6">#Days_Low#</TD>

        <TD BGCOLOR="##EFD6C6">#Volume#</TD>

    </TR>

    </CFOUTPUT>

</TABLE>

And now for the main tag :


<!--- This is the CF_StockGrabberLite tag (simplified version) --->

<CFSET Symbol_List = attributes.TickerSymbols>

<CFSET QueryName = attributes.QueryName>


<CFHTTP METHOD="GET"

   URL="http://quote.yahoo.com/download/quotes.csv?Symbols=
      #Symbol_List#&format=sl1d1t1c1ohgv&ext=.csv"

   NAME="caller.#QueryName#"

   COLUMNS="Symbol,Last_Traded_Price,Last_Traded_Date,Last_Traded_Time,
      Change,Opening_Price,Days_High,Days_Low,Volume"

   DELIMITER=","

   TEXTQUALIFIER="""">

The above example takes the query that gets generated by CFHTTP and returns it to the calling ColdFusion template with the query name that was passed to the tag as an attribute. This allows users to dynamically name the query that will later be returned by the tag.

This method for returning the output of a Custom Tag works great for queries that are prebuilt by tags such as CFHTTP and CFQUERY. Unfortunately, not all data that you wish to return as a query comes neatly packaged that way. An alternative scenario involves a prebuilt query that needs to have information added or parsed out before being returned to the calling ColdFusion template. To further explain what I mean, let's look at the last example in which we built CF_StockGrabberLite. The tag works fine until you try to pass an invalid ticker symbol through CFHTTP to Yahoo. Doing this causes the tag to crash.

The reason for this is that invalid ticker symbols, index symbols and mutual fund symbols cause the value N/A to appear in the Volume field. In and of itself, this might seem harmless. However, if you consider that CFHTTP has a parameter for text qualification, the potential for problems arises. Yahoo returns the quotes requested by the tag as a comma-delimited list of qualified values. That is, all text in the file is surounded by double quotes. Numbers are left as is. Passing one of the above-mentioned "problem symbols" causes an unqualified N/A to appear in the volume field. Because CFHTTP expects all text to be qualified, it chokes when it encounteres the unqualified N/A.

To get around this, we need to turn off text qualification in CFHTTP by setting the parameter TEXTQUALIFIER="". If we were to leave it at that, we woud quickly notice that all of our query results were surrounded in quotes - not too practical for displaying stock quotes. We could parse out all of the quotes in the calling template after the results are returned from the Custom Tag, but that would be tedious and necessary in every application that uses the tag. So, what we need to do is to parse out the quotes in the Custom Tag before they are returned to the calling ColdFusion template.

There is no easy way to do a search and replace inside of a query before the results are output. One of the better workarounds is to move the query results to an array, do the search and replace, and repopulate the query with the updated data. This may sound like a huge undertaking, but it is pretty easy once you get the hang of it. Going with the same example we have been using, let's modify our CF_StockGrabberLite tag to strip all quotes from the CFHTTP result query before returning them to the Calling ColdFusion template. For this example, no changes need to be made to the ColdFusion template calling the CF_StockGrabberLite tag. Here's the revised tag:


<!--- This is the CF_StockGrabberLite tag (simplified version) --->

<CFSET Symbol_List = attributes.TickerSymbols>

<CFSET QueryName = attributes.QueryName>


<!--- If you want to see the tag break, change the textqualifier 
   to """" and insert an invalid ticker like xxxx --->

<CFHTTP METHOD="GET"

URL="http://quote.yahoo.com/download/quotes.csv?Symbols=
   #Symbol_List#&format=sl1d1t1c1ohgv&ext=.csv"

NAME="#QueryName#"

COLUMNS="Symbol,Last_Traded_Price,Last_Traded_Date,Last_Traded_Time,
   Change,Opening_Price,Days_High,Days_Low,Volume"

DELIMITER=","

TEXTQUALIFIER="">

<!--- RECREATE QUERY --->

<CFSET MyArray = ArrayNew(1)>

<CFSET MyQuery = Evaluate("#QueryName#")>

<CFSET NewColumns = "#MyQuery.ColumnList#">

<CFSET NewQuery = QueryNew(NewColumns)>

<!--- ADD ROWNUMBER TO END OF EACH ROW'S VALUE --->

<CFOUTPUT QUERY="MyQuery">

  <CFSET MyArray[CurrentRow] = NumberFormat(CurrentRow, "000009")>

  <CFSET Temp = QueryAddRow(NewQuery)>

</CFOUTPUT>

 
<!--- POPULATE THE NEW QUERY WITH THE INFO FROM THE OLD ONE, 
   BUT WITH ALL QUOTES REMOVED --->

<CFLOOP FROM=1 TO=#MyQuery.RecordCount# INDEX="This">

  <CFSET Row = Val(Right(MyArray[This], 6))>

  <CFLOOP LIST="#MyQuery.ColumnList#" INDEX="Col">

    <CFSET Temp = QuerySetCell(NewQuery, Col, Replace(Evaluate
       ("MyQuery.#Col#[Row]"),"""","","All"), This)>

  </CFLOOP>

</CFLOOP>


<!--- PASS QUERY WITH QUOTATION MARKS REMOVED BACK TO 
   CALLING TEMPLATE --->

<CFSET "Caller.#QueryName#" = NewQuery>

Armed with the above techniques, it is possible to write Custom Tags that do some pretty amazing things. For more examples of Custom Tag wizardry, visit Allaire's Tag Gallery.

Published Sep. 17, 2003— Reads 3,871
Copyright © 2003 SYS-CON Media, Inc. — All Rights Reserved.
Syndicated stories and blog feeds, all rights reserved by the author.
About Rob Brooks-Bilson


Add Your Feedback

In order to post a comment you need to be registered and logged in.

Register | Sign-in

Reader Feedback: Page 1 of 1

Subscribe to the World's Most Powerful Newsletters
Subscribe to Our Rss Feeds & Get Your SYS-CON News Live!
Click to Add our RSS Feeds to the Service of Your Choice:
Google Reader or Homepage Add to My Yahoo! Subscribe with Bloglines Subscribe in NewsGator Online
myFeedster Add to My AOL Subscribe in Rojo Add 'Hugg' to Newsburst from CNET News.com Kinja Digest View Additional SYS-CON Feeds
Publish Your Article! Please send it to editorial(at)sys-con.com!

Advertise on this site! Contact advertising(at)sys-con.com! 201 802-3021

SYS-CON Featured Whitepapers

ADS BY GOOGLE

Breaking Java News
Fujitsu Announces Free Access to Its Enhanced Cloud BPM Platform for Solution Providers and Enterprise Teams
Fujitsu Interstage BPM Version 11 Lets Businesses Proactively "Sense and Respond" to Change
Money Worries put 75 per cent of Brits at Risk of Avoidable Sight Loss
Obese Britain Blind to Risk of Sight Loss
Zebinix a Novel Once Daily Anti-Epileptic Launched Today in the UK

ADVERTISE   |   MAGAZINE SUBSCRIPTIONS   |   FREE BREAKING-NEWSLETTERS!   |   SYS-CON.TV   |   BLOG-N-PLAY!   |   WEBCAST   |   EDUCATION   |   RESEARCH

.NET Developer's Journal - .NETDJ   |   ColdFusion Developer's Journal - CFDJ   |   Eclipse Developer's Journal - EDJ   |   Enterprise Open Source Magazine - EOS
Open Web Developer's Journal - OPENWEB   |   iPhone Developer's Journal - iPHONE   |   Virtualization - Virtualization   |   Java Developer's Journal - JDJ   |   Linux.SYS-CON.com
PowerBuilder Developer's Journal - PBDJ   |   SEO / SEM Journal - SJ   |   SOAWorld Magazine - SOAWM   |   IT Solutions Guide - ITSG   |   Symbian Developer's Journal - SDJ
WebLogic Developer's Journal - WLDJ   |   WebSphere Journal - WJ   |   Wireless Business & Technology - WBT   |   XML-Journal - XMLJ   |   Internet Video - iTV
Flex Developer's Journal - Flex   |   AJAXWorld Magazine - AWM   |   Silverlight Developer's Journal - SLDJ   |   PHP.SYS-CON.com   |   Web 2.0 Journal - WEB2
Apache   |   CMS   |   CRM   |   HP   |   Oracle Journal   |   Perl   |   Python   |   Red Hat   |   Ruby on Rails   |   SAP   |   SaaS

SYS-CON MEDIA:   ABOUT US   |   CONTACT US   |   COMPANY NEWS   |   CAREERS   |   SITE MAP
SYS-CON EVENTS:   |  AJAXWorld Conference & Expo  |  iPhone Developer Summit  |  Cloud Computing Conference & Expo  |  SOA World Conference & Expo  |  Virtualization Conference & Expo
INTERNATIONAL SITES:   India  |  U.K.  |  Canada  |  Germany  |  France  |  Australia  |  Italy  |  Spain  |  Netherlands  |  Brazil  |  Belgium
 Terms of Use & Our Privacy Statement     About Newsfeeds / Video Feeds
Copyright ©1994-2008 SYS-CON Publications, Inc. All Rights Reserved. All marks are trademarks of SYS-CON Media.
Reproduction in whole or in part in any form or medium without express written permission of SYS-CON Publications, Inc. is prohibited.
 
close this window