For example I have array ads and inside it has images
ads
images
url = someurl
title = sometitle
*here I want to add prop = someprop
images
url = someurl
title = sometitle
*here I want to add prop = someprop
ads
images
url = someurl
title = sometitle
*here I want to add prop = someprop
Now I loop
<cfloop array="ads" index="i">
<cfloop array="i.images" index="j">
<cfif somecondition>
<cfset prop = 'yes'>
<cfelse>
<cfset prop = 'no'>
</cfif>
<cfset ArrayAppend(i.images[j],prop)> ???
</cfloop>
</cfloop>
I tried several things with the ArrayAppend, tried a StructAppend, but apparently I am unable to understand how I would go about.
You were close. You can simply set the prop on the item in the images loop. This is assuming that the items in the i.images array are structures.
<cfloop array="ads" index="i">
<cfloop array="i.images" index="j">
<cfif somecondition>
<cfset j.prop = 'yes'>
<cfelse>
<cfset j.prop = 'no'>
</cfif>
</cfloop>
</cfloop>
I'm not aware of an array attribute for cfloop, but I think this is what you're after
<cfloop from="1" to="#arrayLen(ads)#" index="i" step="1">
<cfset ads[i]["newprop"] = newpropvalue>
</cfloop>
I'm creating an XML document from database entries using ColdFusion and when the XML is created the < and > are in the format of < and >. So before it creates the XML is there a way to change the < to a <?
Below is the code and an example of the output:
<cfquery name="messages" datasource="showcase_Uk">
select * from t_items where pid = 2 and spid = 45
</cfquery>
<cfset myStruct = StructNew() />
<cfset mystruct.link = "http://showcase.com" />
<cfset myStruct.title = "Examples" />
<cfset mystruct.description = "Examples from UK Showcase" />
<cfset mystruct.pubDate = Now() />
<cfset mystruct.version = "rss_2.0" />
<cfset myStruct.item = ArrayNew(1) />
<cfloop query="messages">
<cfset myStruct.item[currentRow] = StructNew()>
<cfset myStruct.item[currentRow].guid = structNew()>
<cfset myStruct.item[currentRow].guid.isPermaLink="YES">
<cfset myStruct.item[currentRow].guid.value = xmlFormat(#messages.id#)>
<cfset myStruct.item[currentRow].pubDate = createDate(year(#messages.uploadDate#), month(#messages.uploadDate#), day(#messages.uploadDate#))>
<cfset myStruct.item[currentRow].title = xmlFormat(#messages.name#)>
<cfset myStruct.item[currentRow].description = StructNew() />
<cfset myStruct.item[currentRow].description.value = xmlFormat(#messages.description#)>
</cfloop>
<cffeed action="create" name="#myStruct#" overwrite="true" xmlVar="myXML">
<cffile action="write" file="e:\domains\showcase.com\wwwroot\ukshowcasefeed.xml" nameconflict="overwrite" output="#XMLFormat(myXML)#">
<cffile action="read" file="e:\domains\showcase.com\wwwroot\ukshowcasefeed.xml" variable="myfile">
<cfoutput>#myfile#</cfoutput>
Then here is a screenshot of the code it produces:
I've tried ReplaceNoCase and that doesn't change it at all. I believe it maybe something to do with Regex but I don't really know.
Simple answer:
Don't XmlFormat() when you write the file, that's what causes the double encoding you see.
Longer answer:
I recommend you use mapping to create your feed:
<cfquery name="messages" datasource="showcase_Uk">
select
id, uploadDate, name, description, 'yes' as isPermaLink
from
t_items
where
pid = 2 and spid = 45
</cfquery>
<cfset feedMeta = {
version: "rss_2.0",
title: "Examples",
link: "http://showcase.com",
publisheddate: Now(),
description: "Examples from UK Showcase"
}>
<cfset feedMap = {
title: "name",
content: "description",
publisheddate: "uploadDate",
id: "id",
idpermalink: "isPermaLink"
}>
<cffeed
action="create"
properties="#feedMeta#" columnMap="#feedMap#" query="#messages#"
xmlvar="feedXml"
>
<cffile
action="write"
file="#ExpandPath('/ukshowcasefeed.xml')#" nameconflict="overwrite" charset="utf-8"
output="#feedXml#"
>
Note the easy declarative approach to feed creation. No loops, no manual struct creation, only data-driven mapping of input to output.
Also note the charset="utf-8" on the <cffile>, that's essential if you don't want to run into encoding problems.
If you modify your query so that it has the correct column names right-away, then you don't even need the feedMap structure:
<cfquery name="messages" datasource="showcase_Uk">
select
id,
'yes' as idpermalink
uploadDate as publisheddate,
name as title,
description as content
from
t_items
where
pid = 2 and spid = 45
</cfquery>
<cffeed
action="create"
properties="#feedMeta#" query="#messages#"
xmlvar="feedXml"
>
I have a few session variables I need setup for permissions and only the userID, userName and sessionAdmin variables are making it through. I do a cfdump and see all of the variables set to 0, which is the cfparam default. I also can not get the page to redirect to my sample address.
login.cfm
<cfif isDefined("FORM.login")>
<cfset Encryptpwd = Encrypt(FORM.password, application.PsswrdKy)>
<cfset loginInfo = CFCmain.getLogin(FORM.username,Encryptpwd)>
<cflock timeout=20 scope="session" type="exclusive">
<cfset session.UserName = loginInfo.username>
<cfset session.userid = loginInfo.id>
<cfset session.Access_admin = loginInfo.superadmin>
<cfset session.Access_var1 = loginInfo.var1>
<cfset session.Access_var2 = loginInfo.var2>
<cfset session.Access_var3 = loginInfo.var3>
<cfset session.Access_var4= loginInfo.var4>
<cfset session.Access_agency = loginInfo.agency>
</cflock>
<cflocation url="http://www.google.com">
</cfif>
and main.cfc where my variables are pulled from the db
<cffunction name= "getLogin" access="remote" returntype="any" >
<cfargument name="uname" type="string">
<cfargument name="pwd" type="string">
<cfquery name="getdata" datasource="#application.db#">
select * from users2 where username = '#arguments.uname#' and password = '#arguments.pwd#'
</cfquery>
<cfreturn getdata>
</cffunction>
For me it looks like the variable FORM.login is not defined!?
try:
<cfif isDefined("FORM.login")>
<cfdump var="hello">
<cfabort>
....
if you don't see the "hello", FORM.login is not defined...
try also:
<cfdump var="#form#" abort>
to see what is defined in the form scope.
And how others said, use cfqueryparam!! (security)
<cfquery name="getdata" datasource="#application.db#">
select *
from users2
where username = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.uname#">
and password = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.pwd#">
</cfquery>
Trying to display structExcelResult["strUrl"] created by the function on my .cfm page.
<cffunction name="getBuyerReport" output="false" access="public" returntype="struct">
<cfargument name="intRegionId" required="yes">
<cfargument name="intBuyerId" required="yes">
<cfargument name="intStage" required="yes">
<cfargument name="strSortField" required="yes">
<cfargument name="strSortDirection" required="yes">
<cfset var structExcelResult = StructNew()>
<cfset var qRead="" />
<cfquery name="qRead" datasource="#variables.dsn#">
SELECT CONVERT(varchar,t.RECEIVED_DATE,101) AS [Received Date]
, t.REQUISITION_NO AS [Requisition Number]
, t.REQUISITION_TITLE AS [Requisition Title]
, t.TECHNICAL_AUTHORITY_NAME AS [Technical Authority]
, bm.BID_START_DATE AS [Solicitation Date]
, bm.BID_END_DATE AS [Closing Date]
, CAST(t.REQ_AMOUNT AS MONEY) AS [Requisition Value]
, CAST(t.APPROVAL_AMOUNT AS MONEY) AS [Approval Value]
, t.CURRENT_STAGE AS [Current Stage]
, CONVERT(varchar,t.ESTIMATED_AWARD_DATE,101) AS [Estimated Award Date]
, replace(replace(n.NOTE,CHAR(13),''),CHAR(10),'') as [Comments]
, DATEDIFF(day, t.RECEIVED_DATE, getdate()) AS [Age of Requisition (days)]
, cb.USER_NAME as [Buyer Name]
, o.OFFICE_LOCATION_NAME as [Office Location]
FROM VW__TOMBSTONES__CLIENT_CODES t
LEFT OUTER JOIN TB__OFFICE_LOCATIONS o
ON o.ID = t.OFFICE__ID
LEFT OUTER JOIN TB__USERS cb
ON t.CURRENT_BUYER__ID = cb.ID
LEFT OUTER JOIN TB__BID_MANAGEMENTS bm
ON bm.TB__TOMBSTONES__ID = t.ID
LEFT OUTER JOIN TB__REQUISITIONS r
ON r.TOMBSTONES__ID = t.ID
LEFT OUTER JOIN TB__NOTES n
ON n.REQUISITION__ID = r.ID
AND t.CURRENT_STAGE = n.NOTE_TYPE
WHERE t.CURRENT_STAGE <= 4
AND n.NOTE_TYPE BETWEEN 1 AND 4
AND t.REGION__ID = #arguments.intRegionId#
</cfquery>
<!--- Create new spreadsheet --->
<cfset sObj = SpreadsheetNew()>
<!--- Excel Functions --->
<cfset countFormula="COUNTA(A8:A20000)">
<cfset sumFormula="SUM(G2:G2000)">
<!--- Create header row --->
<cfset SpreadsheetMergeCells(sObj,1,1,1,2)>
<cfset SpreadsheetSetCellValue(sObj, "BUYER REGISTER REPORT",1,1)>
<cfset SpreadsheetFormatRow(sObj, {bold=TRUE, alignment="center"}, 1)>
<cfset SpreadsheetSetCellValue(sObj, "Report Generated Date:",3,1)>
<cfset SpreadsheetFormatCell(sObj, {bold=TRUE, alignment="right"}, 3,1)>
<cfset SpreadsheetSetCellValue(sObj, "#ToString(DateFormat(now(), "mmmm d yyyy"))#",3,2 )>
<cfset SpreadsheetFormatCell(sObj, {bold=TRUE, alignment="left"}, 3,2)>
<cfset SpreadsheetSetCellValue(sObj, "Number of Requisitions:",4,1)>
<cfset SpreadsheetFormatCell(sObj, {bold=TRUE, alignment="right"}, 4,1)>
<cfset SpreadsheetSetCellFormula(sObj,countFormula, 4, 2)>
<cfset SpreadsheetFormatCell(sObj, {bold=TRUE, alignment="left"}, 4,2)>
<cfset SpreadsheetSetCellValue(sObj, "Value of Requisitions:",5,1 )>
<cfset SpreadsheetFormatCell(sObj, {bold=TRUE, alignment="right"}, 5,1)>
<cfset SpreadsheetSetCellFormula(sObj,sumFormula, 5, 2)>
<cfset SpreadsheetFormatCell(sObj, {bold=TRUE, alignment="left"}, 5,2)>
<cfset SpreadsheetFormatCell(sObj, {dataformat="$##,##0.00"}, 5,2)>
<cfset SpreadsheetAddRow(sObj, "" )>
<cfset SpreadsheetAddRow(sObj, "RECEIVED DATE,REQUISITION NUMBER,REQUISITION TITLE,TECHNICAL AUTHORITY,SOLICITATION DATE,CLOSING DATE,REQUISITION VALUE,APPROVAL VALUE,CURRENT STAGE,ESTIMATED AWARD DATE,COMMENTS,AGE OF REQUISITION (DAYS),BUYER NAME,OFFICE LOCATION")>
<cfset SpreadsheetFormatRow(sObj, {bold=TRUE}, 7)>
<!--- Add orders from query --->
<cfset SpreadsheetAddRows(sObj, qRead)>
<cfset SpreadsheetFormatColumns(sObj, {dataformat="$##,##0.00"}, "7-8")>
<cfset SpreadsheetFormatColumns(sObj, {alignment="center"}, "9-10")>
<cfset SpreadsheetFormatColumns(sObj, {alignment="center"}, "12-15")>
<!--- Excel document naming and storing location --->
<cfset strDir=GetDirectoryFromPath(GetCurrentTemplatePath())&"/../assets/generatedXLS/">
<cfset strFilePrepend = "-BuyerReport-" />
<cfset strFileNameStamp = "Galileo" & "#strFilePrepend#" & "#ToString(DateFormat(now(), "yy-mm-dd"))#" & "-#ToString(TimeFormat(now(), "HHmmss"))#" & ".xls"/>
<cfspreadsheet action="write"
filename="#strDir##strFileNameStamp#"
name="sObj"
overwrite="true"
sheetname="Active (Stages 1-4)">
<cfset structExcelResult["strURL"] = "/web_apps/app/assets/generatedXLS/" & #strFileNameStamp# />
<cfset structExcelResult["strNoRecordsFoundMsg"] = "" />
<cfreturn structExcelResult>
How do I fetch that data (structExcelResult["strURL"]) and display it on my .cfm page?
I'm new at this and going through Ben Forta books... Thanks!
Since you have a cfreturn in your code, I'll assume that was meant to have been wrapped in cffunction.
You can call a cffunction a couple of different ways. It could be on the same .cfm page that you're on:
<cffunction name="sayHello" output="false">
<cfargument name="username" type="string" required="false" default="Anonymous" />
<cfreturn "Hello, " & username />
</cffunction>
<cfoutput>#sayHello( 'Charlie' )#</cfoutput>
However, it's more likely that your function is part of a ColdFusion Component (CFC). To call a function that's part of a CFC, you first have to instantiate the CFC:
<cfset myCFC = createObject( 'component', 'path.to.my.cfc' ) />
Now you can call any method that resides in the CFC via:
<cfoutput>#myCFC.myFunction( 'foo' )#</cfoutput>
Going back to my first (very simple) example, let's say the sayHello() function resided in the Greeting.cfc file that was at /com/Greeting.cfc.
<cfset greeting = createObject( 'component', 'com.greeting' ) />
<cfoutput>#greeting.sayHello( 'Charlie' )#</cfoutput>
You can use anything you'd like for the name. It doesn't have to be myCFC or greeting. It's just a variable that represents a hook into your component.
Hope that helps.
UPDATED CODE TO LATEST ITERATION
The following function consumes a webservice that returns address details based on zip code (CEP). I'm using this function to parse the xml and populate an empty query with the address details. I would like to know if there is a more elegant way to achieve the same result. It seems to be a waste to create an empty query and populate it...
Any ideas could my method be modified or the code factored/simplified?
<!--- ****** ACTION: getAddress (consumes web-service to retrieve address details) --->
<cffunction name="getAddress" access="remote" returntype="any" output="false">
<!--- Defaults: strcep (cep (Brazilian zip-code) string webservice would look for), search result returned from webservice --->
<cfargument name="cep" type="string" default="00000000">
<cfset var searchResult = "">
<cfset var nodes = "">
<cfset var cfhttp = "">
<cfset var stateid = 0>
<cfset var tmp = structNew()>
<!--- Validate cep string --->
<cfif IsNumeric(arguments.cep) AND Len(arguments.cep) EQ 8>
<cftry>
<!--- Consume webservice --->
<cfhttp method="get" url="http://www.bronzebusiness.com.br/webservices/wscep.asmx/cep?strcep=#arguments.cep#"></cfhttp>
<cfset searchResult = xmlparse(cfhttp.FileContent)>
<cfset nodes = xmlSearch(searchResult, "//tbCEP")>
<!--- If result insert address data into session struct --->
<cfif arrayLen(nodes)>
<cfset tmp.streetType = nodes[1].logradouro.XmlText>
<cfset tmp.streetName = nodes[1].nome.XmlText>
<cfset tmp.area = nodes[1].bairro.XmlText>
<cfset tmp.city = nodes[1].cidade.XmlText>
<cfset tmp.state = nodes[1].uf.XmlText>
<cfset tmp.cep = arguments.cep>
<!--- Get state id and add to struct --->
<cfset stateid = model("state").findOneByStateInitials(tmp.state)>
<cfset tmp.stateid = stateid.id>
<cfreturn tmp>
</cfif>
<!--- Display error if any --->
<cfcatch type="any">
<cfoutput>
<h3>Sorry, but there was an error.</h3>
<p>#cfcatch.message#</p>
</cfoutput>
</cfcatch>
</cftry>
</cfif>
</cffunction>
<!--- ****** END ACTION getAddress --->
The calling code:
<!--- Get address data based on CEP --->
<cfset session.addressData = getAddress(cep=params.newMember.cep)>
I can't test this because I don't have an example XML file / CEP to test with, but here is a minor rewrite that addresses four things:
Instead of using cfparam and some strange "params" structure, you should pass the CEP into the function as an argument.
The function shouldn't directly modify session data. Instead, you should return the result and let the calling code assign it to the session (or wherever else it might be needed). I'll show this in a 2nd code example.
Cache the xml result per CEP -- assuming this doesn't change often. (You'll have to improve it further if you want time-based manual cache invalidation, but I can help add that if necessary)
Don't use StructInsert. It's not necessary and you're just writing it the long way for the sake of writing it the long way. There is no benefit.
Again, this isn't tested, but hopefully it's helpful:
<cffunction name="getAddress" access="remote" returntype="any" output="false">
<cfargument name="cep" type="string" default="00000000" /><!--- (cep (Brazilian zip-code) string webservice would look for) --->
<cfset var searchResult = "">
<cfset var nodes = "">
<cfset var cfhttp = "">
<cfset var stateid = 0 />
<cfset var tmp = structNew()>
<!--- Validate cep string --->
<cfif IsNumeric(arguments.cep) AND Len(arguments.cep) EQ 8>
<cfif not structKeyExists(application.cepCache, arguments.cep)><!--- or cache is expired: you'd have to figure this part out --->
<!--- Consume webservice --->
<cftry>
<cfhttp method="get" url="http://www.bronzebusiness.com.br/webservices/wscep.asmx/cep?strcep=#arguments.cep#" />
<cfset searchResult = xmlparse(cfhttp.FileContent)>
<cfset nodes = xmlSearch(searchResult, "//tbCEP")>
<!--- If result insert address data into session struct --->
<cfif arrayLen(nodes)>
<cfset tmp.streetType = nodes[1].logradouro.XmlText />
<cfset tmp.streetName = nodes[1].nome.XmlText />
<cfset tmp.area = nodes[1].bairro.XmlText />
<cfset tmp.city = nodes[1].cidade.XmlText />
<cfset tmp.state = nodes[1].uf.XmlText />
<cfset tmp.cep = arguments.cep />
<!--- Get state id and add to struct --->
<cfset stateid = model("state").findOneByStateInitials(session.addressData.state)>
<cfset tmp.stateid = stateid.id />
</cfif>
<cfreturn duplicate(tmp) />
<!--- Display error if any --->
<cfcatch type="any">
<h3>Sorry, but there was an error.</h3>
<p>#cfcatch.message#</p>
</cfcatch>
</cftry>
<cfelse>
<!--- cache exists and is not expired, so use it --->
<cfreturn duplicate(application.cepCache[arguments.cep]) />
</cfif>
</cfif>
<!---
<!--- Redirect to page two of the sign up process --->
<cfset redirectTo(controller="assine", action="perfil")>
--->
</cffunction>
Notice that I commented out the redirect you had at the end. That's because with my function, you'll be returning a value, and the redirect should be done after that, like so:
<cfset session.addressData = getAddress("some-CEP-value") />
<cfset redirectTo(controller="assine", action="perfil")>
If you're going to leave out the caching (As you say in a comment you will), then here is a version that makes no attempt at caching:
<cffunction name="getAddress" access="remote" returntype="any" output="false">
<cfargument name="cep" type="string" default="00000000" /><!--- (cep (Brazilian zip-code) string webservice would look for) --->
<cfset var searchResult = "">
<cfset var nodes = "">
<cfset var cfhttp = "">
<cfset var stateid = 0 />
<cfset var tmp = structNew()>
<!--- Validate cep string --->
<cfif IsNumeric(arguments.cep) AND Len(arguments.cep) EQ 8>
<!--- Consume webservice --->
<cftry>
<cfhttp method="get" url="http://www.bronzebusiness.com.br/webservices/wscep.asmx/cep?strcep=#arguments.cep#" />
<cfset searchResult = xmlparse(cfhttp.FileContent)>
<cfset nodes = xmlSearch(searchResult, "//tbCEP")>
<!--- If result insert address data into session struct --->
<cfif arrayLen(nodes)>
<cfset tmp.streetType = nodes[1].logradouro.XmlText />
<cfset tmp.streetName = nodes[1].nome.XmlText />
<cfset tmp.area = nodes[1].bairro.XmlText />
<cfset tmp.city = nodes[1].cidade.XmlText />
<cfset tmp.state = nodes[1].uf.XmlText />
<cfset tmp.cep = arguments.cep />
<!--- Get state id and add to struct --->
<cfset stateid = model("state").findOneByStateInitials(session.addressData.state)>
<cfset tmp.stateid = stateid.id />
</cfif>
<cfreturn duplicate(tmp) />
<!--- Display error if any --->
<cfcatch type="any">
<h3>Sorry, but there was an error.</h3>
<p>#cfcatch.message#</p>
</cfcatch>
</cftry>
</cfif>
<!---
<!--- Redirect to page two of the sign up process --->
<cfset redirectTo(controller="assine", action="perfil")>
--->
</cffunction>
Note that I did leave in the use of duplicate(). What this does is return a duplicate of the object (in this case, the struct). This is much more important when you start to work on applications where you're passing complex values into and out of functions over and over again. Using duplicate() causes things to be passed by value instead of by reference. It may not bite you in this case, but it's a good habit to get into.
I would also still use the function argument and return a value -- but it's arguable that this is my personal preference. In a way it is. I believe that a function should be fully encapsulated; a total "black box". You give it some input and it gives you back some output. It should not modify anything outside of itself. (Again, just my opinion.)
So assuming you're using this function as part of a larger multi-step process, you should still use it the same way I've described above. The only difference is that you're setting the session variable outside of the function body. Just as previously:
<cfset session.addressData = getAddress("some-CEP-value") />
<cfset redirectTo(controller="assine", action="perfil")>
That looks pretty straightforward. CF doesn't (yet?) have any magical XML-to-Query functions, but that would be pretty cool. If you wanted, you could probably write up an XSL transform to go from XML to WDDX so that you could use the cfwddx tag ... but that's probably putting the cart before the horse.
You need to move your arrayLen() if block into the try block. As it stands, if the cfhttp tag throws an error, the nodes variable will be a string and not an array, thus causing the arrayLen() to throw another error.
Minor nitpick: I wouldn't add a row to the query until inside the arrayLen() block. That way, the calling code can check recordCount to see if the result was a success.
Beyond that ... that's pretty much how it's done.