-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathRssService.cfc
642 lines (542 loc) · 21.8 KB
/
RssService.cfc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
<!---
Name : rss.cfc
Version : 0.1
Author : Raymond Camden
Created : December 8, 2004
Last Updated : February 7, 2007
History : Fix for bug with isSimpleValue barfing on a string with xml (rkc 1/5/05)
Added generation code (rkc last few weeks)
Don't use GUID if permalink is false (rkc 10/17/06)
Fixed bugs in Atom support. Added support for standard enclosures. (bpr 2/7/06)
Purpose : General handler for RSS data.
Note: I cannot give enough thanks to Roger B. ([email protected]). He was
an incredible amount of help in turning this from a toy to something that actually
worked well and followed the standards (although I didn't go quite as far as I could).
Note: Various methods have output=true on them. This is to help debug. They will be turned
off once I hit 1.0.
To Do:
generateRSS() (obvious)
--->
<cfcomponent displayName="RSS" hint="Allows for various ways to handle RSS data." output="false">
<!--- Used for the default query --->
<cfset variables.defaultQueryList = "title,description,link,date,enclosure">
<cffunction name="generateRSS" access="public" returnType="string" output="true"
hint="Translates a query into RSS.">
<cfargument name="type" type="string" required="true" hint="RSS Type: RSS091,RSS092,RSS1,RSS2, or Atom3">
<cfargument name="data" type="query" required="true" hint="Query with columns: link,title,body,date,subject">
<cfargument name="metadata" type="struct" required="true" hint="Struct used for metadata">
<!--- default query cols --->
<cfif not listFindNoCase(arguments.data.columnList,"link")>
<cfset queryAddColumn(arguments.data,"link",arrayNew(1))>
</cfif>
<cfif not listFindNoCase(arguments.data.columnList,"title")>
<cfset queryAddColumn(arguments.data,"title",arrayNew(1))>
</cfif>
<cfif not listFindNoCase(arguments.data.columnList,"body")>
<cfset queryAddColumn(arguments.data,"body",arrayNew(1))>
</cfif>
<cfif not listFindNoCase(arguments.data.columnList,"date")>
<cfset queryAddColumn(arguments.data,"date",arrayNew(1))>
</cfif>
<cfif not listFindNoCase(arguments.data.columnList,"subject")>
<cfset queryAddColumn(arguments.data,"subject",arrayNew(1))>
</cfif>
<cfif arguments.type is "RSS091">
<cfreturn generateRSS_RSS(arguments.data, arguments.metadata,"0.91")>
<cfelseif arguments.type is "RSS092">
<cfreturn generateRSS_RSS(arguments.data, arguments.metadata,"0.92")>
<cfelseif arguments.type is "RSS1">
<cfreturn generateRSS_RSS1(arguments.data, arguments.metadata)>
</cfif>
</cffunction>
<cffunction name="generateRSS_RSS" access="private" returnType="string" output="true"
hint="Translates a query into RSS. This is used for RSS 0.91 and RSS 0.92">
<cfargument name="data" type="query" required="true" hint="Query with columns: link,title,body,date,subject">
<cfargument name="metadata" type="struct" required="true" hint="Struct with keys: title,link,description">
<cfargument name="version" type="string" required="true" hint="0.91, or 0.92">
<cfset var header = "">
<cfset var footer = "">
<cfset var meta = "">
<cfset var body = "">
<cfset var tBody = "">
<cfset var result = "">
<cfsavecontent variable="header">
<cfoutput>
<?xml version="1.0" encoding="ISO-8859-1" ?>
<rss version="#arguments.version#">
<channel>
</cfoutput>
</cfsavecontent>
<cfsavecontent variable="footer">
<cfoutput>
</channel>
</rss>
</cfoutput>
</cfsavecontent>
<!--- first handle metadata --->
<cfset meta = renderMeta(arguments.metadata)>
<cfloop query="arguments.data">
<cfsavecontent variable="tBody">
<cfoutput>
<item>
<title>#xmlFormat(arguments.data.title)#</title>
<link>#xmlFormat(arguments.data.link)#</link>
<description>#xmlFormat(arguments.data.body)#</description>
<cfif arguments.version is 0.92><category>#xmlFormat(arguments.data.subject)#</category></cfif>
</item>
</cfoutput>
</cfsavecontent>
<cfset body = body & tBody>
</cfloop>
<cfset result = trim(header) & trim(meta) & trim(body) & trim(footer)>
<cfreturn result>
</cffunction>
<cffunction name="generateRSS_RSS1" access="private" returnType="string" output="true"
hint="Translates a query into RSS. This is used for RSS 1.0">
<cfargument name="data" type="query" required="true" hint="Query with columns: link,title,body,date,subject">
<cfargument name="metadata" type="struct" required="true" hint="Struct with keys: title,link,description">
<cfset var header = "">
<cfset var footer = "">
<cfset var meta = "">
<cfset var body = "">
<cfset var tBodyTop = "">
<cfset var tBodyBottom = "">
<cfset var result = "">
<cfset var z = getTimeZoneInfo()>
<cfsavecontent variable="header">
<cfoutput>
<?xml version="1.0" encoding="ISO-8859-1" ?>
<rdf:RDF
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns##"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns="http://purl.org/rss/1.0/"
>
</cfoutput>
</cfsavecontent>
<cfsavecontent variable="footer">
<cfoutput>
</rdf:RDF>
</cfoutput>
</cfsavecontent>
<!--- first handle metadata --->
<cfset meta = renderMeta(arguments.metadata)>
<!--- We loop through twice, once for top portion, one for body portion --->
<cfloop query="arguments.data">
<cfsavecontent variable="tBodyTop">
<cfoutput>
<rdf:li rdf:resource="#xmlFormat(arguments.data.link)#" />
</cfoutput>
</cfsavecontent>
<cfset body = body & tBodyTop>
</cfloop>
<!--- Mody body to correctly wrap content. --->
<cfsavecontent variable="body">
<cfoutput>
<cfif structKeyExists(arguments.metadata,"link")>
<channel rdf:about="#xmlFormat(arguments.metadata.link)#">
<cfelse>
<channel rdf:about="">
</cfif>
#trim(meta)#
<items>
<rdf:Seq>
#body#
</rdf:Seq>
</items>
</channel>
</cfoutput>
</cfsavecontent>
<!--- Now handle the next portion of the body --->
<cfloop query="arguments.data">
<cfsavecontent variable="tBodyBottom">
<cfoutput>
<item rdf:about="#xmlFormat(arguments.data.link)#">
<title>#xmlFormat(arguments.data.title)#</title>
<description>#xmlFormat(arguments.data.body)#</description>
<link>#xmlFormat(arguments.data.link)#</link>
<dc:date>#dateFormat(arguments.data.date,"yyyy-mm-dd")#T#timeFormat(arguments.data.date,"HH:mm:ss")#<cfif z.utcHourOffSet lt 0>+#numberFormat(z.utcHourOffset,"00")*-1#<cfelse>-#numberFormat(z.utcHourOffset,"00")#</cfif>:00</dc:date>
<dc:subject>#xmlFormat(arguments.data.subject)#</dc:subject>
</item>
</cfoutput>
</cfsavecontent>
<cfset body = body & trim(tBodyBottom)>
</cfloop>
<cfset result = trim(header) & trim(body) & trim(footer)>
<cfreturn result>
</cffunction>
<cffunction name="getEntries" access="public" returnType="query" output="true"
hint="Translates a RSS feed into a simple query.">
<cfargument name="xmlData" type="any" required="true" hint="XML Ob, XML String, or URL">
<cfset var rssType = "">
<cfset var result = queryNew(variables.defaultQueryList)>
<cfset arguments.xmlData = getXML(arguments.xmlData)>
<cfset rssType = getRssType(arguments.xmlData)>
<!--- What we do is determined by the type --->
<cfswitch expression="#rssType.type#">
<cfcase value="rss">
<cfreturn getEntriesRSS(arguments.xmlData)>
</cfcase>
<cfcase value="atom">
<cfreturn getEntriesAtom(arguments.xmlData)>
</cfcase>
<cfdefaultcase>
<cfreturn result>
</cfdefaultcase>
</cfswitch>
</cffunction>
<cffunction name="getEntriesAtom" access="private" returnType="query" output="true"
hint="Handles Atom feeds">
<cfargument name="xmlData" type="any" required="true" hint="XML Ob">
<cfset var entries = "">
<cfset var result = queryNew(variables.defaultQueryList)>
<cfset var x = 1>
<cfset var i = 1>
<cfset var node = "">
<cfset entries = xmlSearch(arguments.xmlData,"//*[local-name() = 'entry']")>
<cfloop index="x" from="1" to="#arrayLen(entries)#">
<cfset node = structNew()>
<cfset node.title = entries[x].title.xmlText>
<!--- Link comes from entries[x].link.XmlAttributes.rel --->
<cfset node.link = "">
<cfset node.enclosure = "">
<cfif structKeyExists(entries[x],"link")>
<!--- loop through N links --->
<cfloop index="i" from="1" to="#arrayLen(entries[x].link)#">
<cfif entries[x].link[i].xmlAttributes.rel is "alternate">
<cfset node.link = entries[x].link[i].xmlAttributes.href>
<cfelseif entries[x].link[i].xmlAttributes.rel is "enclosure">
<cfset node.enclosure = entries[x].link[i].xmlAttributes.href>
</cfif>
</cfloop>
</cfif>
<!--- try for summary first --->
<cfif structKeyExists(entries[x],"summary")>
<cfset node.description = entries[x].summary.xmlText>
<cfelseif structKeyExists(entries[x],"content")>
<!--- handle potential xml content --->
<cfif structKeyExists(entries[x].content.xmlAttributes,"mode") and entries[x].content.xmlAttributes.mode is "xml">
<cfset node.description = getEmbeddedHTML(entries[x].content.xmlChildren)>
<cfelse>
<cfset node.description = entries[x].content.xmlText>
</cfif>
<cfelse>
<cfset node.description = "">
</cfif>
<cfif structKeyExists(entries[x],"published")>
<cfset node.date = entries[x].published.xmlText>
<cfelseif structKeyExists(entries[x],"updated")>
<cfset node.date = entries[x].updated.xmlText>
<cfelse>
<cfset node.date = "">
</cfif>
<cfset queryAddRow(result)>
<cfset querySetCell(result,"title",node.title)>
<cfset querySetCell(result,"description",node.description)>
<cfset querySetCell(result,"link",node.link)>
<cfset querySetCell(result,"enclosure",node.enclosure)>
<cfset querySetCell(result,"date",node.date)>
</cfloop>
<cfreturn result>
</cffunction>
<cffunction name="getEntriesRSS" access="private" returnType="query" output="true"
hint="Handles RSS feeds">
<cfargument name="xmlData" type="any" required="true" hint="XML Ob">
<cfset var items = "">
<cfset var result = queryNew(variables.defaultQueryList)>
<cfset var x = 1>
<cfset var node = "">
<cfset items = xmlSearch(arguments.xmlData,"//*[local-name() = 'item']")>
<cfloop index="x" from="1" to="#arrayLen(items)#">
<cfset node = structNew()>
<cfif structKeyExists(items[x],"title")>
<cfset node.title = items[x].title.XmlText>
<cfelse>
<cfset node.title = "">
</cfif>
<cfif structKeyExists(items[x],"description")>
<cfset node.description = items[x].description.XmlText>
<cfelse>
<cfset node.description = "">
</cfif>
<!--- For the link, guid type priority --->
<cfif structKeyExists(items[x],"guid") and (not structKeyExists(items[x].guid.xmlAttributes, "isPermaLink") or items[x].guid.xmlAttributes.isPermaLink)>
<cfset node.link = items[x].guid.XmlText>
<cfelseif structKeyExists(items[x],"link")>
<cfset node.link = items[x].link.XmlText>
<!--- rss 0.92 allows source --->
<cfelseif structKeyExists(items[x],"source") and structKeyExists(items[x].source.XmlAttributes,"url")>
<cfset node.link = items[x].source.XmlAttributes.url>
<cfelse>
<cfset node.link = "">
</cfif>
<!--- rss 0.92 allows enclosure --->
<cfset node.enclosure = "">
<cfif structKeyExists(items[x],"enclosure") and structKeyExists(items[x].enclosure.XmlAttributes,"url")>
<cfset node.enclosure = items[x].enclosure.XmlAttributes.url>
</cfif>
<cfif structKeyExists(items[x],"pubdate")>
<cfset node.date = items[x].pubDate.XmlText>
<!--- try for dc:date --->
<cfelseif structKeyExists(items[x],"dc:date")>
<cfset node.date = items[x]["dc:date"].XmlText>
<cfelse>
<cfset node.date = "">
</cfif>
<cfset queryAddRow(result)>
<cfset querySetCell(result,"title",node.title)>
<cfset querySetCell(result,"description",node.description)>
<cfset querySetCell(result,"link",node.link)>
<cfset querySetCell(result,"date",node.date)>
</cfloop>
<cfreturn result>
</cffunction>
<cffunction name="getRSSMeta" access="public" returnType="struct" output="true"
hint="Gets meta info on an RSS feed.">
<cfargument name="xmlData" type="any" required="true" hint="XML Ob, XML String, or URL">
<cfset var result = structNew()>
<cfset var rssType = "">
<cfset arguments.xmlData = getXML(arguments.xmlData)>
<cfset rssType = getRSSType(arguments.xmlData)>
<!--- What we do is determined by the type --->
<cfswitch expression="#rssType.type#">
<cfcase value="rss">
<cfif rssType.version is 2>
<cfreturn getRSSMetaRss2(arguments.xmlData)>
<cfelseif rssType.version is 0.91>
<cfreturn getRSSMetaRss09(arguments.xmlData)>
<cfelseif rssType.version is 0.92>
<cfreturn getRSSMetaRss09(arguments.xmlData,"0.92")>
<cfelseif rssType.version is 1>
<cfreturn getRSSMetaRss1(arguments.xmlData)>
</cfif>
</cfcase>
<cfcase value="atom">
<cfreturn getRssMetaAtom(arguments.xmlData)>
</cfcase>
<cfdefaultcase>
<cfreturn result>
</cfdefaultcase>
</cfswitch>
<cfreturn result>
</cffunction>
<cffunction name="getRSSMetaAtom" access="private" returnType="struct" output="true"
hint="Gets meta info for Atom feeds.">
<cfargument name="xmlData" type="any" required="true" hint="XML object.">
<cfset var result = structNew()>
<cfset var reqList = "title,link,author,modified">
<cfset var optList = "contributor,tagline,id,generator,copyright,info">
<cfset var key = "">
<cfset var x = "">
<!--- required items --->
<cfloop index="key" list="#reqList#">
<cfif not structKeyExists(arguments.xmlData.feed,key)>
<cfset result[key] = "">
<cfelse>
<cfif key is "link">
<!--- we only want the rel/alternate link --->
<cfloop index="x" from="1" to="#arrayLen(arguments.xmlData.feed.link)#">
<cfif arguments.xmlData.feed.link[x].XmlAttributes.rel is "alternate">
<cfset result["link"] = arguments.xmlData.feed.link[x].XmlAttributes.href>
</cfif>
</cfloop>
<cfelseif key is "author">
<cfset result["author"] = arguments.xmlData.feed.author.name.XmlText>
<cfelse>
<cfset result[key] = arguments.xmlData.feed[key].XmlText>
</cfif>
</cfif>
</cfloop>
<!--- optional items --->
<cfloop index="key" list="#optList#">
<cfif structKeyExists(arguments.xmlData.feed,key)>
<cfif key is "info">
<cfset result[key] = arguments.xmlData.feed.info.XmlChildren[1].toString()>
<cfelse>
<cfset result[key] = arguments.xmlData.feed[key].XmlText>
</cfif>
</cfif>
</cfloop>
<cfreturn result>
</cffunction>
<cffunction name="getRSSMetaRss09" access="private" returnType="struct" output="true"
hint="Gets meta info for RSS 0.91 and 0.92 feeds.">
<cfargument name="xmlData" type="any" required="true" hint="XML object.">
<cfargument name="version" type="string" required="false" default="0.91" hint="Version">
<cfset var result = structNew()>
<cfset var reqList = "title,link,description,language">
<cfset var optList = "copyright,docs,image,lastBuildDate,managingEditor,pubDate,rating,skipDays,skipHours,textinput,webMaster">
<cfset var key = "">
<cfset var i = "">
<!--- modify reqList if version is 0.92 --->
<cfif arguments.version is 0.92>
<cfset reqList = listDeleteAt(reqList, listFindNoCase(reqList, "language"))>
<cfset optList = listAppend(optList, "language")>
</cfif>
<!--- required items --->
<cfloop index="key" list="#reqList#">
<cfif not structKeyExists(arguments.xmlData.rss.channel,key)>
<cfset result[key] = "">
<cfelse>
<cfset result[key] = arguments.xmlData.rss.channel[key].XmlText>
</cfif>
</cfloop>
<!--- optional items --->
<cfloop index="key" list="#optList#">
<cfif structKeyExists(arguments.xmlData.rss.channel,key)>
<cfif key is "image">
<!--- image is a complex struct, just copy via children --->
<cfloop index="i" from="1" to="#arrayLen(arguments.xmlData.rss.channel[key].XmlChildren)#">
<cfset result[key][arguments.xmlData.rss.channel[key].XmlChildren[i].XmlName] = arguments.xmlData.rss.channel[key].XmlChildren[i].XmlText>
</cfloop>
<cfelse>
<cfset result[key] = arguments.xmlData.rss.channel[key].XmlText>
</cfif>
</cfif>
</cfloop>
<cfreturn result>
</cffunction>
<cffunction name="getRSSMetaRss1" access="private" returnType="struct" output="true"
hint="Gets meta info for RSS 1 feeds.">
<cfargument name="xmlData" type="any" required="true" hint="XML object.">
<cfset var result = structNew()>
<cfset var reqList = "title,link,description">
<cfset var optList = "image,textinput">
<cfset var key = "">
<!--- required items --->
<cfloop index="key" list="#reqList#">
<cfif not structKeyExists(arguments.xmlData["rdf:RDF"].channel,key)>
<cfset result[key] = "">
<cfelse>
<cfset result[key] = arguments.xmlData["rdf:RDF"].channel[key].XmlText>
</cfif>
</cfloop>
<!--- optional items --->
<cfloop index="key" list="#optList#">
<cfif structKeyExists(arguments.xmlData["rdf:RDF"].channel,key)>
<cfset result[key] = arguments.xmlData["rdf:RDF"].channel[key].XmlText>
</cfif>
</cfloop>
<cfreturn result>
</cffunction>
<cffunction name="getRSSMetaRss2" access="private" returnType="struct" output="true"
hint="Gets meta info for RSS 2 feeds.">
<cfargument name="xmlData" type="any" required="true" hint="XML object.">
<cfset var result = structNew()>
<cfset var reqList = "title,link,description">
<cfset var optList = "language,copyright,managingEditor,webMaster,pubDate,lastBuildDate,category,generator,docs,cloud,ttl,image,rating,textInput,skipHours,skipDays">
<cfset var key = "">
<!--- required items --->
<cfloop index="key" list="#reqList#">
<cfif not structKeyExists(arguments.xmlData.rss.channel,key)>
<cfset result[key] = "">
<cfelse>
<cfset result[key] = arguments.xmlData.rss.channel[key].XmlText>
</cfif>
</cfloop>
<!--- optional items --->
<cfloop index="key" list="#optList#">
<cfif structKeyExists(arguments.xmlData.rss.channel,key)>
<cfset result[key] = arguments.xmlData.rss.channel[key].XmlText>
</cfif>
</cfloop>
<cfreturn result>
</cffunction>
<cffunction name="getRSSType" access="public" returnType="struct" output="true"
hint="Determines the RSS feed type.">
<cfargument name="xmlData" type="any" required="true" hint="XML Ob, XML String, or URL">
<cfset var result = structNew()>
<cfset arguments.xmlData = getXML(arguments.xmlData)>
<cfset result.type = "Unknown">
<cfset result.version = "">
<!--- RSS 0.91, 0.92, 2.0 --->
<cfif structKeyExists(arguments.xmlData,"rss") and
structKeyExists(arguments.xmlData.rss.xmlAttributes,"version")
and listFind("0.91,0.92,2.0",arguments.xmlData.rss.xmlAttributes.version)>
<cfset result.type = "RSS">
<cfset result.version = arguments.xmlData.rss.xmlAttributes.version>
</cfif>
<!--- RSS 1.0 --->
<cfif structKeyExists(arguments.xmlData,"rdf:RDF") and
arguments.xmlData["rdf:RDF"].xmlAttributes.xmlns is "http://purl.org/rss/1.0/">
<cfset result.type = "RSS">
<cfset result.version = "1.0">
</cfif>
<!--- Atom X --->
<cfif structKeyExists(arguments.xmlData,"feed")>
<!--- For Atom, we insist on version but don't care what it is --->
<cfif structKeyExists(arguments.xmlData.feed.xmlAttributes,"xmlns") and (arguments.xmlData.feed.xmlAttributes.xmlns is "http://www.w3.org/2005/Atom" or arguments.xmlData.feed.xmlAttributes.xmlns is "http://purl.org/atom/ns##")>
<cfset result.type = "Atom">
<cfset result.version = "1.0">
</cfif>
</cfif>
<cfreturn result>
</cffunction>
<!--- UTILITY FUNCTIONS --->
<cffunction name="getEmbeddedHTML" access="private" returnType="string" output="true"
hint="Used to get a string from an html embedded xml packet.">
<cfargument name="data" type="array" required="true">
<cfset var str = "">
<cfset var i = "">
<cfloop index="i" from="1" to="#arrayLen(arguments.data)#">
<cfset str = str & arguments.data[i].toString()>
</cfloop>
<cfreturn str>
</cffunction>
<cffunction name="getXML" access="private" returnType="any" output="true"
hint="Allows you to pass an XML ob, XML string, or URL and get an XML object back.">
<cfargument name="data" type="any" required="true">
<!--- <cfset arguments.data = "http://spanishwizards.com/fakeurl" /> --->
<!--- <cfdump var="#arguments.data#"><cfabort /> --->
<cfif isXMLDoc(arguments.data)>
<cfreturn arguments.data>
</cfif>
<cfif isURL(arguments.data)>
<cftry>
<cfhttp url="#arguments.data#" useragent="Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.0.2) Gecko/20060308 Firefox/1.5.0.2">
<cfset arguments.data = cfhttp.fileContent>
<cfcatch></cfcatch>
</cftry>
</cfif>
<cftry>
<cfif isSimpleValue(trim(arguments.data)) and isXml(trim(arguments.data))>
<cfreturn xmlParse(arguments.data)>
<cfelse>
<cfreturn xmlParse(getDefaultXml())>
</cfif>
<cfcatch>
<cfoutput>#htmlCodeFormat(arguments.data)#</cfoutput><cfdump var="argument: #arguments.data#" /><cfdump var="#cfcatch#" /><cfdump var="#cgi#" /><cfabort>
</cfcatch>
</cftry>
<cfthrow type="rss.cfc" message="The data passed was not a valid XML object, string, or URL pointing to XML., #arguments.data#">
</cffunction>
<cffunction name="isURL" access="private" returnType="boolean" output="false"
hint="Checks to see if a string is a URL. Written by Nathan Dintenfass.">
<cfargument name="str" type="string" required="true">
<cfreturn reFindNoCase("^(((https?:|ftp:|gopher:)\/\/))[-[:alnum:]\?%,\.\/&##!@:=\+~_]+[A-Za-z0-9\/]$",arguments.str) NEQ 0>
</cffunction>
<cffunction name="getDefaultXml" access="private" returnType="any" output="false"
hint="">
<cfset var defaultXml = "" />
<cfsavecontent variable="defaultXml">
<?xml version="1.0"?>
<data>
<display>Nothing available</display>
</data>
</cfsavecontent>
<cfreturn trim(defaultXml) />
</cffunction>
<cffunction name="renderMeta" access="private" returnType="string" output="true"
hint="Recursively output a struct in XML format.">
<cfargument name="data" type="struct" required="true">
<cfset var s = "">
<cfset var k = "">
<cfloop item="k" collection="#arguments.data#">
<cfif isSimpleValue(arguments.data[k])>
<cfset s = s & "<#lcase(k)#>#arguments.data[k]#</#lcase(k)#>">
<cfelseif isStruct(arguments.data[k])>
<cfset s = s & "<#lcase(k)#>" & renderMeta(arguments.data[k]) & "</#lcase(k)#>">
</cfif>
</cfloop>
<cfreturn s>
</cffunction>
</cfcomponent>