I am consuming a WCF made with ASP.NET 4.0 and trying to use the resulting data in Coldfusion 9.
Using the following code I am able to return what appears to be an object, but not the data itself as XML (as I was expecting).
<cfscript>
wcf2 = CreateObject("webservice","http://demo.opendrt.co.uk/Mobisoft.TAPIMobiRouter.WCF.Silver/MBRServices.svc?wsdl", "BasicHttpBinding_IMBRBookingServices");
variables.myResult2 = wcf2.GetPassengerBookings("Austin,Jason", "14/11/2010", "14/11/2012");
XMLContent = variables.myResult2.ResponseData.Booking;
</cfscript>
The Booking element of ResponseData contains several entries, each of which contains other data, some of which is nested in further children of booking.
XMLContent = variables.myResult2.ResponseData.getBooking(2).DropOffLocation.ShortName;
Will return the value of that item alone, as will
XMLContent = variables.myResult2.ResponseData.getBooking(2).BookingPassengerInfo.PassengerRef;
Is it possible to use the returned data as a whole, converting it to a recordset or similar within Coldfusion, something along the lines of:
<cfoutput query="XMLContent">
<h1>#PassengerRef#</h1>
<p>#ShortName#<p>
</cfoutput>
Thanks,
Paul
I have something that works, whether it is the most economical way to achieve it I am not sure so am open to any other ideas.
<cfscript>
wcf2 = CreateObject("webservice","http://demo.opendrt.co.uk/Mobisoft.TAPIMobiRouter.WCF.Silver/MBRServices.svc?wsdl", "BasicHttpBinding_IMBRBookingServices");
variables.myResult2 = wcf2.GetPassengerBookings("Austin,Jason", "14/11/2010", "14/11/2012");
bookings = variables.myResult2.ResponseData.Booking;
</cfscript>
<cfset result = QueryNew("BookingRef, PassengerRef, PickupDateTime","varchar, varchar, varchar")>
<cfloop from="1" to="#ArrayLen(bookings)#" index="i">
<!--- Add a row to the query.--->
<cfset QueryAddRow(result)>
<cfset QuerySetCell(result, "BookingRef", bookings[i].BookingRef)>
<cfset QuerySetCell(result, "PassengerRef", bookings[i].BookingPassengerInfo.PassengerRef)>
<cfset QuerySetCell(result, "PickupDateTime", bookings[i].PickupDateTime)>
</cfloop>
<table>
<tr>
<th>Booking Ref</th>
<th>Passenger Ref</th>
<th>PickupDateTime</th>
</tr>
<cfoutput query="result">
<tr>
<td>#BookingRef#</td>
<td>#PassengerRef#</td>
<td>#PickupDateTime#</td>
</tr>
</cfoutput>
</table>
Related
I am getting used to ColdFusion. It appears cfscript makes a developer's life easier.
In my cfscript function, I need to:
Run a query "SELECT A, B from MyTable"
For each row of this query, create a new component on the fly that has three properties A, B, and C. Here, C is computed within the function.
Return an array of the new components.
Here is the pseudo-code:
<cfquery name="myq" datasource="mydsn">
SELECT A, B
FROM MyTable
</cfquery>
<cfscript>
function MyFunc() {
// Do the magic and return the array
}
</cfscript>
I am guessing I would use this function as I would use a query:
<cfset myarray=MyFunc() />
<cfloop index="i" from="1" to="#arrayLen(myarray)#">
#myarray.A# <br />
#myarray.B# <br />
#myarray.C# <br />
</cfloop>
I would appreciate it if you can suggest me how I can accomplish this. I have been searching through Adobe documentation but haven't found a good example that I can relate to. Thank you in advance for your help.
I know I'm not suppose to just paste the link, but it's really all you need.
Query in cfscript
Loop Query in cfscript (CF10)
Loop Query in cfscript (CF9)
Then just use new xxx() for new object, ArrayAppend() for constructing an array and return it.
Good luck, let us know if you run into any other problems.
You probably want something like
<cfoutput>
<cfloop index="i" from="1" to="#arrayLen(myarray)#">
#myarray.A[i]# <br />
#myarray.B[i]# <br />
#myarray.C[i]# <br />
</cfloop>
</cfoutput>
Overall you should consider returning a query rather than an array
<cfscript>
query function MyFunc() {
// Do the magic and return the array
}
</cfscript>
Then process it by
<cfset myQuery = MyFunc()>
<cfoutput query="myQuery">
#A# <br />
#B# <br />
#C# <br />
</cfoutput>
One rule of thumb in ColdFusion is: Queries are more powerful than arrays of structs. You can process them that way, but you will miss out on some very power features such as having <cfoutput> iterating over a query.
I have a .PPT (PowerPoint, transferrable to ODP or PPTX) file with speaker notes on every slide. I want to extract the entire presentation into something dynamic so I can create a speaker cheat sheet for running on a phone or table while I talk (thumbnail of the slide with speaker notes). I do this just often enough to HATE doing it by hand.
This is almost easy enough with <cfpresentation format="html" showNotes="yes"> which splits the PPT up into HTML pages and creates an image for every slide. cfpresentation, however, does not transfer the speaker notes, they are lost in translation.
I have also tried <cfdocument> which has no options for preserving slide notes once it converts to PDF.
Is there a way to get the notes out of the PowerPoint file from within ColdFusion?
The simplest solution:
Convert the PowerPoint presentation to OpenOffice ODP format. That's a ZIP file. CFML can unzip it and inside there's a content.xml file which contains the slides and the notes, so CFML can extract the notes from that format.
Given the CFDOCUMENT functionality, perhaps ColdFusion can even convert the PPT to ODP for you?
There's no way to do this directly in CF. You can do this by dropping to the underlying Java. I stand corrected. Using the showNotes attribute on the <cfpresentation> tag, should add the notes to the HTML.
As an alternative, or if that doesn't work for some reason, you should be able to use Apache POI to do this, although you may need to use a more recent version of poi than shipped with your version of coldfusion, which may require some additional work.
public static LinkedList<String> getNotes(String filePath) {
LinkedList<String> results = new LinkedList<String>();
// read the powerpoint
FileInputStream fis = new FileInputStream(filePath);
SlideShow slideShow = new SlideShow(is);
fis.close();
// get the slides
Slide[] slides = ppt.getSlides();
// loop over the slides
for (Slide slide : slides) {
// get the notes for this slide.
Notes notes = slide.getNotesSheet();
// get the "text runs" that are part of this slide.
TextRun[] textRuns = notes.getTextRuns();
// build a string with the text from all the runs in the slide.
StringBuilder sb = new StringBuilder();
for (TextRun textRun : textRuns) {
sb.append(textRun.getRawText());
}
// add the resulting string to the results.
results.add(sb.toString());
}
return results;
}
Carrying over complex formatting may be a challenge (bulleted lists, bold, italics, links, colors, etc.), as you'll have to dig much deeper into TextRuns, and the related API's and figure how to generate HTML.
CFPRESENTATION (at least as of version 9) does have a showNotes attribute, but you'd still have to parse the output. Depending on the markup of the output, jQuery would make short work of grabbing what you want.
Felt bad that my above answer didn't work out so I dug a little bit. It's a little dated, but it works. PPTUtils, which is based on the apache library that #Antony suggested. I updated this one function to do what you want. You may have to tweak it a bit to do exactly what you want, but I like the fact that this utility returns the data to you in data format rather than in HTML which you'd have to parse.
And just in case, here is the POI API reference I used to find the "getNotes()" function.
<cffunction name="extractText" access="public" returntype="array" output="true" hint="i extract text from a PPT by means of an array of structs containing an array element for each slide in the PowerPoint">
<cfargument name="pathToPPT" required="true" hint="the full path to the powerpoint to convert" />
<cfset var hslf = instance.loader.create("org.apache.poi.hslf.HSLFSlideShow").init(arguments.pathToPPT) />
<cfset var slideshow = instance.loader.create("org.apache.poi.hslf.usermodel.SlideShow").init(hslf) />
<cfset var slides = slideshow.getSlides() />
<cfset var notes = slideshow.getNotes() />
<cfset var retArr = arrayNew(1) />
<cfset var slide = structNew() />
<cfset var i = "" />
<cfset var j = "" />
<cfset var k = "" />
<cfset var thisSlide = "" />
<cfset var thisSlideText = "" />
<cfset var thisSlideRichText = "" />
<cfset var rawText = "" />
<cfset var slideText = "" />
<cfloop from="1" to="#arrayLen(slides)#" index="i">
<cfset slide.slideText = structNew() />
<cfif arrayLen(notes)>
<cfset slide.notes = notes[i].getTextRuns()[1].getRawText() />
<cfelse>
<cfset slide.notes = "" />
</cfif>
<cfset thisSlide = slides[i] />
<cfset slide.slideTitle = thisSlide.getTitle() />
<cfset thisSlideText = thisSlide.getTextRuns() />
<cfset slideText = "" />
<cfloop from="1" to="#arrayLen(thisSlideText)#" index="j">
<cfset thisSlideRichText = thisSlideText[j].getRichTextRuns() />
<cfloop from="1" to="#arrayLen(thisSlideRichText)#" index="k">
<cfset rawText = thisSlideRichText[k].getText() />
<cfset slideText = slideText & rawText />
</cfloop>
</cfloop>
<cfset slide.slideText = duplicate(slideText) />
<cfset arrayAppend(retArr, duplicate(slide)) />
</cfloop>
<cfreturn retArr />
</cffunction>
After moving and backing up my photo collection a few times I have several duplicate photos, with different filenames in various folders scattered across my PC. So I thought I would write a quick CF (9) page to find the duplicates (and can then add code later to allow me to delete them).
I have a couple of queries:-
At the moment I am just using file size to match the image file, but I presume matching EXIF data or matching hash of image file binary would be more reliable?
The code I lashed together sort of works, but how could this be done to search outside web root?
Is there a better way?
p
<cfdirectory
name="myfiles"
directory="C:\ColdFusion9\wwwroot\images\photos"
filter="*.jpg"
recurse="true"
sort="size DESC"
type="file" >
<cfset matchingCount=0>
<cfset duplicatesFound=0>
<table border=1>
<cfloop query="myFiles" endrow="#myfiles.recordcount#-1">
<cfif myfiles.size is myfiles.size[currentrow + 1]>
<!---this file is the same size as the next row--->
<cfset matchingCount = matchingCount + 1>
<cfset duplicatesFound=1>
<cfelse>
<!--- the next file is a different size --->
<!--- if there have been matches, display them now --->
<cfif matchingCount gt 0>
<cfset sRow=#currentrow#-#matchingCount#>
<cfoutput><tr>
<cfloop index="i" from="#sRow#" to="#currentrow#">
<cfset imgURL=#replace(directory[i], "C:\ColdFusion9\wwwroot\", "http://localhost:8500/")#>
<td><img height=200 width=200 src="#imgURL#\#name[i]#"></td>
</cfloop></tr><tr>
<cfloop index="i" from="#sRow#" to="#currentrow#">
<td width=200>#name[i]#<br>#directory[i]#</td>
</cfloop>
</tr>
</cfoutput>
<cfset matchingCount = 0>
</cfif>
</cfif>
</cfloop>
</table>
<cfif duplicatesFound is 0><cfoutput>No duplicate jpgs found</cfoutput></cfif>
This is pretty fun task, so I've decided to give it a try.
First, some testing results on my laptop with 4GB RAM, 2x2.26Ghz CPU and SSD: 1,143 images, total 263.8MB.
ACF9: 8 duplicates, took ~2.3 s
Railo 3.3: 8 duplicates, took ~2.0 s (yay!)
I've used great tip from this SO answer to pick the best hashing option.
So, here is what I did:
<cfsetting enablecfoutputonly="true" />
<cfset ticks = getTickCount() />
<!--- this is great set of utils from Apache --->
<cfset digestUtils = CreateObject("java","org.apache.commons.codec.digest.DigestUtils") />
<!--- cache containers --->
<cfset checksums = {} />
<cfset duplicates = {} />
<cfdirectory
action="list"
name="images"
directory="/home/trovich/images/"
filter="*.png|*.jpg|*.jpeg|*.gif"
recurse="true" />
<cfloop query="images">
<!--- change delimiter to \ if you're on windoze --->
<cfset ipath = images.directory & "/" & images.name />
<cffile action="readbinary" file="#ipath#" variable="binimage" />
<!---
This is slow as hell with any encoding!
<cfset checksum = BinaryEncode(binimage, "Base64") />
--->
<cfset checksum = digestUtils.md5hex(binimage) />
<cfif StructKeyExists(checksums, checksum)>
<!--- init cache using original on 1st position when duplicate found --->
<cfif NOT StructKeyExists(duplicates, checksum)>
<cfset duplicates[checksum] = [] />
<cfset ArrayAppend(duplicates[checksum], checksums[checksum]) />
</cfif>
<!--- append current duplicate --->
<cfset ArrayAppend(duplicates[checksum], ipath) />
<cfelse>
<!--- save originals only into the cache --->
<cfset checksums[checksum] = ipath />
</cfif>
</cfloop>
<cfset time = NumberFormat((getTickcount()-ticks)/1000, "._") />
<!--- render duplicates without resizing (see options of cfimage for this) --->
<cfoutput>
<h1>Found #StructCount(duplicates)# duplicates, took ~#time# s</h1>
<cfloop collection="#duplicates#" item="checksum">
<p>
<!--- display all found paths of duplicate --->
<cfloop array="#duplicates[checksum]#" index="path">
#HTMLEditFormat(path)#<br/>
</cfloop>
<!--- render only last duplicate, they are the same image any way --->
<cfimage action="writeToBrowser" source="#path#" />
</p>
</cfloop>
</cfoutput>
Obviously, you can easily use duplicates array to review the results and/or run some cleanup job.
Have fun!
I would recommend split up the checking code into a function which only accepts a filename.
Then use a global struct for checking for duplicates, the key would be "size" or "size_hash" and the value could be an array which will contain all filenames that matches this key.
Run the function on all jpeg files in all different directories, after that scan the struct and report all entries that have more than one file in it's array.
If you want to show an image outside your webroot you can serve it via < cfcontent file="#filename#" type="image/jpeg">
I want to find out the details of scheduled tasks running on 5 or 6 coldfusion web-servers, by just writing a single page on one of them. Is there any way to do it?
It might be done by reading cron.xml on all of them.
I came across with following code
<cflock name="alltasks" type="exclusive" timeout="10">
<cfscript>
factory = CreateObject("java","coldfusion.server.ServiceFactory");
cron_service = factory.CronService;
services = cron_service.listALL();
</cfscript>
This code is good for finding out details for web server on which it will be executed.
I am looking for something similar to this, that will get me details of scheduled tasks running on all web-servers in same network. Thanks!!
You could use the cfschedule tag, and place a page on each server that outputs the scheduled tasks for that machine. You could then use an HTTP request to each server to pick up the tasks it's responsible for and output them to the page on your monitoring server.
<!--- ServerList contains all server's(7,8,9) ipaddress,,, --->
<cfset serverList = 'a.b.c.d, p.q.r.s, ....... , u.v.w.x'>
<cfoutput>
Searched In: #serverList#<br>
<Cfloop list="#serverList#" index="s">
<cfif FileExists('\\#s#\C$\ColdFusion8\lib\neo-cron.xml')>
<cfset pathToFindNeo = '\\#s#\C$\ColdFusion8\lib\neo-cron.xml'>
<cfelseif FileExists('\\#s#\C$\CFusionMX7\lib\neo-cron.xml') >
<cfset pathToFindNeo = '\\#s#\C$\CFusionMX7\lib\neo-cron.xml'>
<cfelseif FileExists('\\#s#\C$\ColdFusion9\lib\neo-cron.xml')>
<cfset pathToFindNeo = '\\#s#\C$\ColdFusion9\lib\neo-cron.xml'>
<cfelseif FileExists('\\#s#\ColdFusion\lib\neo-cron.xml')>
<cfset pathToFindNeo = '\\#s#\ColdFusion\lib\neo-cron.xml'>
<cfelse>
<cfset pathToFindNeo = 0>
</cfif>
<h3>#s# [#pathToFindNeo#]</h3>
<!--- Get the scheduler xml file. It's stored as WDDX in CFroot dir--->
<cfif pathToFindNeo neq 0>
<cffile action="Read" file="#pathToFindNeo#" variable="TaskXML">
<!--- Convert the WDDX to CFML - and array of structs --->
<cfwddx action="WDDX2CFML" input="#TaskXML#" output="GetTasks">
<table border="1" width="100%">
<tr>
<td><strong>Name</strong></td>
<Td><strong>URL</strong></Td>
<td><strong>Interval</strong></td>
<Td><strong>Disabled</strong></Td>
<td><strong>Start Date</strong></td>
<td><strong>Start Time</strong></td>
<td><strong>End Time</strong></td>
<td><strong>Operation</strong></td>
</tr>
<cfloop collection="#GetTasks[1]#" item="key">
<cfif GetTasks[1][key]['disabled'] eq 'NO'>
<tr>
<cfelse>
<tr style="background-color:##CCC">
</cfif>
<td>#key#</td>
<td>#GetTasks[1][key]['url']#</td>
<td>#GetTasks[1][key]['interval']#</td>
<td>#GetTasks[1][key]['disabled']#</td>
<td>#GetTasks[1][key]['start_date']#</td>
<td>#GetTasks[1][key]['start_time']#</td>
<td>
<cfif StructKeyExists(GetTasks[1][key], "end_time")>
#GetTasks[1][key]['end_time']#
<cfelse>
-
</Cfif>
</td>
<td>#GetTasks[1][key]['operation']#</td>
</tr>
</cfloop>
</TABLE>
<CFELSE>
FILE 'neo-cron.xml' NOT FOUND
</cfif>
</Cfloop>
</cfoutput>
What I would probably do is create a cfc on the destination server, that would return the results from the lookup of scheduled tasks into some kind of json, xml, or query that would be available with a set username & password to get the data from 1 server to another, as needed....
The way we take care of this is to add a line to a database table with the URL of the task. If you have all your tasks in the one directory the best way to do this is add the database logging in Application.cfc using the available CGI variables.
This can then be checked against what you expected to run.
Hope that helps!
I'm wondering if anyone has come up with a clean way to generate a breadcrumbs trail in Fusebox. Specifically, is there a way of keeping track of "where you are" and having that somehow generate the breadcrumbs for you? So, for example, if you're executing
/index.cfm?fuseaction=Widgets.ViewWidget&widget=1
and the circuit structure is something like /foo/bar/widgets/ then somehow the system automatically creates an array like:
[
{ title: 'Foo', url: '#self#?fuseaction=Foo.Main' },
{ title: 'Bar', url: '#self#?fuseaction=Bar.Main' },
{ title: 'Widgets', url: '#self#?fuseaction=Widgets.Main' },
{ title: 'Awesome Widget', url: '' }
]
Which can then be rendered as
Foo > Bar > Widgets > Awesome Widget
Right now it seems the only way to really do this is to create the structure for each fuseaction in a fuse of some kind (either the display fuse or a fuse dedicated to creating the crumbtrail).
I'm working with Fusebox for a long time, but still can't understand this part:
circuit structure is something like /foo/bar/widgets/
Any way, once my idea was to use the custom lexicon called "parent" (or anything) for each controller fuseaction, where you put the name of previous level fuseaction.
But as I remember, this method was applicable only when using XML-style circuits, where you can always get any fuseaction info from the global container -- so I didn't make it because of intensive use of no-XMl style.
EDIT: example with lexicon
This will work only with Fusebox 5 traditional.
Let's say we have created following lexicon definition /lexicon/bc/parent.cfm:
<cfscript>
if (fb_.verbInfo.executionMode is "start") {
// validate fb_.verbInfo.attributes contents
if (not structKeyExists(fb_.verbInfo.attributes,"value")) {
fb_throw("fusebox.badGrammar.requiredAttributeMissing",
"Required attribute is missing",
"The attribute 'value' is required, for a 'parent' verb in fuseaction #fb_.verbInfo.circuit#.#fb_.verbInfo.fuseaction#.");
}
// compile start tag CFML code
circuit = fb_.verbInfo.action.getCircuit().getName();
fa = fb_.verbInfo.action.getCircuit().getFuseactions();
fa[#fb_.verbInfo.fuseaction#].parent = circuit & "." & fb_.verbInfo.attributes.value;
} else {
// compile end tag CFML code
}
</cfscript>
Basically this is copy-pasted standard lexicon tag specially for lexicon parent.
Assuming we're using Fusebox 5 skeleton example, contoller can look like:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE circuit>
<circuit access="public" xmlns:bc="bc/">
<postfuseaction>
<do action="layout.mainLayout" />
</postfuseaction>
<fuseaction name="welcome" bc:parent="">
<do action="time.getTime" />
<do action="display.sayHello" />
</fuseaction>
<fuseaction name="widgets" bc:parent="app.welcome">
<do action="display.showWidgets" />
</fuseaction>
<fuseaction name="widget" bc:parent="app.widgets">
<do action="display.showWidget" />
</fuseaction>
</circuit>
It shows how the lexicon used for each fuseaction. Please note that if you wont define the attribute bc:parent it wont appear in custom attributes structure later.
It is possible to use only fuseaction name as parent, if you have all chain within same circuit, it can be easier to use later.
Finally, some quick code to build the stuff. Please see comments, they should be helpful enough.
<!--- path data container with current fuseaction saved --->
<cfset arrBreadcrumbs = [] />
<cfset ArrayAppend(arrBreadcrumbs, attributes.fuseaction) />
<!--- pull the current circuit fuseactions --->
<cfset fuseactions = myFusebox.getApplication().circuits[ListFirst(attributes.fuseaction,'.')].getFuseactions() />
<!--- OR <cfset fuseactions = application.fusebox.circuits[ListFirst(attributes.fuseaction,'.')].getFuseactions()> --->
<!--- pull the current fuseaction custom attributes --->
<cfset fa = ListLast(attributes.fuseaction,'.') />
<cfset customAttributes = fuseactions[fa].getCustomAttributes('bc') />
<!--- save the parent fuseaction name if present -- KEY CHECK IS RECOMMENDED --->
<cfif StructKeyExists(customAttributes, "parent")>
<cfset ArrayPrepend(arrBreadcrumbs, customAttributes.parent) />
</cfif>
<!--- let's say we know that parent is there... --->
<!--- pull the found fuseaction custom attributes --->
<cfset fa = ListLast(customAttributes.parent,'.') />
<cfset customAttributes = fuseactions[fa].getCustomAttributes('bc') />
<!--- save the parent fuseaction name if present --->
<cfif StructKeyExists(customAttributes, "parent")>
<cfset ArrayPrepend(arrBreadcrumbs, customAttributes.parent) />
</cfif>
<!--- render the collected path --->
<cfoutput>
<cfloop index="crumb" from="1" to="#ArrayLen(arrBreadcrumbs)#">
<!--- to have a nice labels you can use another lexicon --->
#arrBreadcrumbs[crumb]# <cfif crumb LT ArrayLen(arrBreadcrumbs)>></cfif>
</cfloop>
</cfoutput>
So the output should look like this: app.welcome > app.widgets > app.widget
Here's something I use...
act_breadcrum.cfm
=============================
<cfscript>
if (NOT structKeyExists(session, 'clickstream'))
{
session.clickstream = arrayNew(1);
}
</cfscript>
<cflock name="addNewPage" type="exclusive" timeout="10">
<cfscript>
if ((arrayIsEmpty(session.clickstream))
OR (compare(myFusebox.originalCircuit, session.clickstream[arrayLen(session.clickstream)].Circuit))
OR (compare(myFusebox.originalFuseaction, session.clickstream[arrayLen(session.clickstream)].Fuseaction))
)
{
if (arrayLen(session.clickstream) EQ 10)
{
temp = arrayDeleteAt(session.clickstream, 1);
}
temp = arrayAppend(session.clickstream, structNew());
session.clickstream[arrayLen(session.clickstream)].Fuseaction = myFusebox.originalFuseaction;
session.clickstream[arrayLen(session.clickstream)].Circuit = myFusebox.originalCircuit;
}
</cfscript>
</cflock>
dsp_Breadcrum.cfm
==========================
<cfoutput>
<center>
<b><u>Last Clicked</u></b><BR>
<cfloop from="#arrayLen(session.clickstream)#" to="1" index="i" step="-1">
<cfset Opaque=i*.2>
<a href="#Myself##session.clickstream[i].Circuit#.#session.clickstream[i].Fuseaction#" style=opacity:#Opaque#>
#session.clickstream[i].Circuit#
</a><BR>
</cfloop>
</center>
</cfoutput>