Printing The Entire jQuery API As A PDF (Using CFDocument And XML Parsing)

Posted February 22, 2007 at 3:00 PM

Tags: ColdFusion, Javascript / DHTML

I am just starting to really get into jQuery, the JavaScript API that makes writing sweet-ass JavaScript easy and fun. As with ColdFusion, I like to really dive into it by plowing through the documentation (yeah, I actually do like reading documentation so I can see what the possibilities are!). jQuery.com and VisualjQuery.com provide great documentation and visual representations of the API, but I wanted something that I could print out and take with me on the train. I am sure that I could find something somewhere, but seeing as VisualjQuery.com runs off of an XML API definition file, I thought I would give it a go with ColdFusion XML and PDF generation (what else would I do for fun???).

The first step was downloading the XML file for the documentation. I got my XML file from Visual jQuery:

http://visualjquery.com/index.xml

Once I had that, it was just a matter of parsing it in with CFXML and outputting a formatting HTML document (that could then be consumed by CFDocument). Ok, maybe that was not quite as easy as it sounds. For one thing, it took me a while to figure out all the little nuances of the XML document (such as what the heck the SEE node was). After a few hours of trial an error, I finally came up with something that was "good enough":

 Launch code in new window » Download code as text file »

  • <!---
  • Create a ColdFusion XML document based on the jQuery XML
  • documentation available at:
  •  
  • http://visualjquery.com/index.xml
  • --->
  • <cfxml variable="xmlDoc">
  • <cfinclude template="./documentation.xml" />
  • </cfxml>
  •  
  •  
  • <!---
  • Get the root XML node of the XML document. This will
  • contain all the categories for the documentation.
  • --->
  • <cfset xmlRoot = XmlDoc.XmlRoot />
  •  
  •  
  • <!--- Output basic CSS for the document. --->
  • <style type="text/css">
  •  
  • body {
  • font: 11px verdana ;
  • }
  •  
  • h2.categoryname {
  • border-bottom: 2px solid #333333 ;
  • font-size: 24px ;
  • }
  •  
  • h2.subcategoryname {
  • border-bottom: 1px solid #333333 ;
  • font-size: 18px ;
  • }
  •  
  • h3 {
  • border-bottom: 1px solid #999999 ;
  • font-size: 14px ;
  • padding-bottom: 3px ;
  • padding-top: 15px ;
  • }
  •  
  • h4 {
  • font-style: italic ;
  • margin: 0px 0px 5px 0px ;
  • }
  •  
  • h5 {
  • font-size: 10px ;
  • margin: 0px 0px 5px 0px ;
  • }
  •  
  • p,
  • ol,
  • ul {
  • margin: 0px 0px 12px 0px ;
  • }
  •  
  • div.methodbody {
  • margin-left: 20px ;
  • }
  •  
  • div.indent {
  • margin-left: 20px ;
  • }
  •  
  • </style>
  •  
  •  
  • <cfoutput>
  •  
  • <h1>
  • jQuery API Documentation
  • </h1>
  •  
  • <!---
  • Get the sections/categories that the documentation is
  • broken up into. Be careful; the documentation has nested
  • categories. By doing a // search, we will be finding all
  • categories regardless of nesting.
  • --->
  • <cfset arrCategories = XmlSearch( xmlRoot, "//cat" ) />
  •  
  •  
  • <!--- Loop over all the sections / categories in the documentation. --->
  • <cfloop
  • index="intCategory"
  • from="1"
  • to="#ArrayLen( arrCategories )#"
  • step="1">
  •  
  • <!--- Get category short hand. --->
  • <cfset xmlCategory = arrCategories[ intCategory ] />
  •  
  • <!--- Get methods for this category. --->
  • <cfset arrMethods = XmlSearch( xmlCategory, "./method" ) />
  •  
  • <!---
  • Get all the sub categories. Remember, the documentation
  • has categories within categories (at times).
  • --->
  • <cfset arrSubCategories = XmlSearch( xmlCategory, "./cat" ) />
  •  
  •  
  • <!---
  • Check to see if we are in a sub category. We will
  • know this is true if the node name of the current
  • node matches the node name of the parent node.
  • --->
  • <cfif (xmlCategory.XmlParent.XmlName EQ xmlCategory.XmlName)>
  •  
  • <!--- We are in a sub category. --->
  • <cfset blnSubCategory = true />
  •  
  • <cfelse>
  •  
  • <!--- We are NOT in a sub category. --->
  • <cfset blnSubCategory = false />
  •  
  • </cfif>
  •  
  •  
  • <!--- Output the category name. --->
  • <h2 class="<cfif blnSubCategory>sub</cfif>categoryname">
  • #xmlCategory.XmlAttributes.Value#
  • </h2>
  •  
  •  
  • <!--- Loop over methods. --->
  • <cfloop
  • index="intMethod"
  • from="1"
  • to="#ArrayLen( arrMethods )#"
  • step="1">
  •  
  • <!--- Get method short hand. --->
  • <cfset xmlMethod = arrMethods[ intMethod ] />
  •  
  • <!--- Get method attributes. --->
  • <cfset arrDescription = XmlSearch( xmlMethod, "./desc" ) />
  • <cfset arrSee = XmlSearch( xmlMethod, "./see" ) />
  • <cfset arrParams = XmlSearch( xmlMethod, "./params" ) />
  • <cfset arrExamples = XmlSearch( xmlMethod, "./examples" ) />
  • <cfset arrBefore = XmlSearch( xmlMethod, "./before" ) />
  • <cfset arrCode = XmlSearch( xmlMethod, "./code" ) />
  • <cfset arrResult = XmlSearch( xmlMethod, "./result" ) />
  • <cfset arrOptions = XmlSearch( xmlMethod, "./options" ) />
  •  
  •  
  • <!--- Ouptut the method name (with param names). --->
  • <h3>
  • #xmlMethod.XmlAttributes.Name#(
  •  
  • <!--- Ouput parameters. --->
  • <cfloop
  • index="intParam"
  • from="1"
  • to="#ArrayLen( arrParams )#"
  • step="1">
  •  
  • <!--- Check to see if this parameter has a name. --->
  • <cfif StructKeyExists( arrParams[ intParam ].XmlAttributes, "Name" )>
  • #arrParams[ intParam ].XmlAttributes.Name#
  • </cfif>
  •  
  • <!---
  • Check to see if we have more than one parameter.
  • We only need a comma for mulitple params.
  • --->
  • <cfif (intParam LT ArrayLen( arrParams ))>
  • ,
  • </cfif>
  •  
  • </cfloop>
  • )
  • </h3>
  •  
  •  
  • <div class="methodbody">
  •  
  • <!--- Check to see if we have a metho description. --->
  • <cfif ArrayLen( arrDescription )>
  •  
  • <p class="methoddescription">
  • #ToString( HtmlEditFormat( arrDescription[ 1 ].XmlText ) ).ReplaceAll(
  • "(\r?\n){2,}",
  • "</p><p class=""methoddescription"">"
  • )#
  • </p>
  •  
  • </cfif>
  •  
  •  
  • <!--- Check to see if we have any parameters. --->
  • <cfif ArrayLen( arrParams )>
  •  
  • <h4>
  • Parameters
  • </h4>
  •  
  • <div class="indent">
  •  
  • <p>
  • <cfloop
  • index="intParam"
  • from="1"
  • to="#ArrayLen( arrParams )#"
  • step="1">
  •  
  • <!--- Get a short hand for the parameters. --->
  • <cfset xmlParameter = arrParams[ intParam ] />
  •  
  • <!--- Get description. --->
  • <cfset arrParamDescription = XmlSearch( xmlParameter, "./desc" ) />
  •  
  • <p>
  •  
  • <cfif StructKeyExists( xmlParameter.XmlAttributes, "Name" )>
  • <strong>#xmlParameter.XmlAttributes.Name#</strong>:
  • </cfif>
  •  
  • <cfif StructKeyExists( xmlParameter.XmlAttributes, "Type" )>
  • ( #xmlParameter.XmlAttributes.Type# ):
  • </cfif>
  •  
  • <cfif ArrayLen( arrParamDescription )>
  • #HtmlEditFormat( arrParamDescription[ 1 ].XmlText )#
  • </cfif>
  •  
  • </p>
  •  
  • </cfloop>
  • </p>
  •  
  • </div>
  •  
  • </cfif>
  •  
  •  
  • <!--- Check to see if we have any method options. --->
  • <cfif ArrayLen( arrOptions )>
  •  
  • <h4>
  • Hash Options
  • </h4>
  •  
  • <div class="indent">
  •  
  • <!--- Loop over options. --->
  • <cfloop
  • index="intOption"
  • from="1"
  • to="#ArrayLen( arrOptions )#"
  • step="1">
  •  
  • <!--- Get a short hand for the option. --->
  • <cfset xmlOption = arrOptions[ intOption ] />
  •  
  • <!--- Get description. --->
  • <cfset arrOptionDescription = XmlSearch( xmlOption, "./desc" ) />
  •  
  • <p>
  •  
  • <cfif StructKeyExists( xmlOption.XmlAttributes, "Name" )>
  • <strong>#xmlOption.XmlAttributes.Name#</strong>:
  • </cfif>
  •  
  • <cfif StructKeyExists( xmlOption.XmlAttributes, "Type" )>
  • ( #xmlOption.XmlAttributes.Type# ):
  • </cfif>
  •  
  • <cfif ArrayLen( arrOptionDescription )>
  • #HtmlEditFormat( arrOptionDescription[ 1 ].XmlText )#
  • </cfif>
  •  
  • </p>
  •  
  • </cfloop>
  •  
  • </div>
  •  
  • </cfif>
  •  
  •  
  • <!--- Check to see if are method has a return type. --->
  • <cfif StructKeyExists( xmlMethod.XmlAttributes, "Type" )>
  •  
  • <h4>
  • Returns
  • </h4>
  •  
  • <div class="indent">
  •  
  • <p>
  • #xmlMethod.XmlAttributes.Type#
  • </p>
  •  
  • </div>
  •  
  • </cfif>
  •  
  •  
  • <!--- Check to see if we have any examples. --->
  • <cfif ArrayLen( arrExamples )>
  •  
  • <!--- Loop over examples. --->
  • <cfloop
  • index="intExample"
  • from="1"
  • to="#ArrayLen( arrExamples )#"
  • step="1">
  •  
  • <!--- Get short hand to example. --->
  • <cfset xmlExample = arrExamples[ intExample ] />
  •  
  • <!--- Get the example attributes. --->
  • <cfset arrExampleDesc = XmlSearch( xmlExample, "./desc" ) />
  • <cfset arrExampleBefore = XmlSearch( xmlExample, "./before" ) />
  • <cfset arrExampleCode = XmlSearch( xmlExample, "./code" ) />
  • <cfset arrExampleResult = XmlSearch( xmlExample, "./result" ) />
  •  
  • <h4>
  • Example
  • </h4>
  •  
  • <div class="indent">
  •  
  • <cfif ArrayLen( arrExampleDesc )>
  •  
  • <p>
  • #HtmlEditFormat( arrExampleDesc[ 1 ].XmlText )#
  • </p>
  •  
  • </cfif>
  •  
  • <cfif ArrayLen( arrExampleCode )>
  •  
  • <p>
  • #HtmlEditFormat( arrExampleCode[ 1 ].XmlText )#
  • </p>
  •  
  • </cfif>
  •  
  • <cfif ArrayLen( arrExampleBefore )>
  •  
  • <h5>
  • Before:
  • </h5>
  •  
  • <p>
  • #HtmlEditFormat( arrExampleBefore[ 1 ].XmlText )#
  • </p>
  •  
  • </cfif>
  •  
  • <cfif ArrayLen( arrExampleResult )>
  •  
  • <h5>
  • Result:
  • </h5>
  •  
  • <p>
  • #HtmlEditFormat( arrExampleResult[ 1 ].XmlText )#
  • </p>
  •  
  • </cfif>
  •  
  • </div>
  •  
  • </cfloop>
  •  
  • </cfif>
  •  
  •  
  • <!--- Check to see if we have any "See Also" examples. --->
  • <cfif ArrayLen( arrSee )>
  •  
  • <h4>
  • See Also
  • </h4>
  •  
  • <div class="indent">
  •  
  • <p>
  • <cfloop
  • index="intSee"
  • from="1"
  • to="#ArrayLen( arrSee )#"
  • step="1">
  •  
  • #arrSee[ intSee ].XmlText#<br />
  •  
  • </cfloop>
  • </p>
  •  
  • </div>
  •  
  • </cfif>
  •  
  • </div>
  •  
  • </cfloop>
  •  
  • </cfloop>
  •  
  • </cfoutput>

I didn't comment the above code that much as I wasn't really that interested in demoing the code. I just wanted to get it working so that I could get my PDF going. Now, once I had that code up and running and producing a nice HTML document, I used the CFDocument to generate that PDF. Assuming the above code was stored in a file named, "parse.cfm", generating the PDF was a sinch!

 Launch code in new window » Download code as text file »

  • <!--- Create a PDF of the parse jQuery documentation. --->
  • <cfdocument
  • format="PDF"
  • pagetype="letter"
  • orientation="portrait"
  • unit="in"
  • encryption="none"
  • fontembed="Yes"
  • backgroundvisible="No">
  •  
  • <!--- Include the parsed jQuery XML. --->
  • <cfinclude template="./parse.cfm" />
  •  
  • </cfdocument>

And that's that! If you want to see the PDF, feel free to download it here.

Download Code Snippet ZIP File

Comments (10)  |  Post Comment  |  Ask Ben  |  Permalink  |  Other Searches  |  Print Page





Reader Comments

Thanks for doing this. My one complaint about that visualjquery site is the lack of a search. A PDF will fix that.

Posted by Matt Williams on Feb 22, 2007 at 4:14 PM


Glad to help. Let me know if you see any way I can improve the PDF.

Posted by Ben Nadel on Feb 22, 2007 at 4:17 PM


don't forget about the jQuery cheat sheets:

http://rip747.wordpress.com/2006/11/30/jquery-cheat-sheets/

Posted by tony petruzzi on Feb 22, 2007 at 6:37 PM


Good work mate, I have been using jQuery for ages and wouldn't use anything else - it is so good. This is really handy as an alterative to the online API documentation.

Posted by Shuns on Feb 22, 2007 at 7:37 PM


@Matt: If you need a searchable version of the API, then go here:

http://jquery.bassistance.de/api-browser/

Rey...

Posted by Rey Bango on Feb 22, 2007 at 11:29 PM


@Ben: Thanks for doing this man. Its a big help :)

Posted by Rey Bango on Feb 22, 2007 at 11:33 PM


@Tony,

Those cheat sheets look awesome! Thanks for pointing me (and everyone else) to those. Once I get through the documentation and get a real taste of everything that is possible, the cheat sheets will provide an invaluable quick look up!

@Rey,

My pleasure dude, jQuery just rocks :)

Posted by Ben Nadel on Feb 23, 2007 at 7:19 AM


Ben, everything is ok, but why you don`t get the documentation from
http://docs.jquery.com/Main_Page ???
As i think it will be better and more fresh.
And there are posted problems and bugs...
Best regards from Russia. =)

Posted by Sam on Nov 24, 2007 at 4:31 AM


@Sam,

When I wrote this post, I was just learning jQuery and I needed something that I could print out and bring home with me; I don't have internet at home, so hand-held documentation is very useful.

It was also an exploration of the use of XML on a large scale document. This later became an experimentation in XSLT:

http://www.bennadel.com/index.cfm?dax=blog:961.view

But yes, I agree, getting the documentation from the live site is the most useful.

Posted by Ben Nadel on Dec 6, 2007 at 8:19 AM


Thank for your PDF it helpful.

Posted by Sambo on Dec 19, 2007 at 12:27 AM


Post Comment  |  Ask Ben


Home   |   Web Log   |   ColdFusion   |   Projects   |   Resume   |   Job Form   |   Search   |   Contact
Epicenter Consulting - Custom Software Solutions for Business Evolution HostMySite.com - The Leader In ColdFusion Hosting