I'm learning how to invoke web-services using coldfusion 7 (later we'll upgrade). I found some free web services to use.
<cfscript>
stArgs = structNew();
stArgs.symbol = "msft";
</cfscript>
<cfinvoke webservice="http://www.webservicex.net/stockquote.asmx?WSDL" method="GetQuote" argumentcollection="#stArgs#" returnvariable="aTemp">
The result from #atemp# is
<StockQuotes><Stock><Symbol>msft</Symbol><Last>47.77</Last><Date>10/20/2015</Date><Time>4:00pm</Time><Change>+0.15</Change><Open>47.41</Open><High>47.81</High><Low>47.02</Low><Volume>30793995</Volume><MktCap>382.06B</MktCap><PreviousClose>47.62</PreviousClose><PercentageChange>+0.31%</PercentageChange><AnnRange>39.72 - 50.05</AnnRange><Earns>1.48</Earns><P-E>32.28</P-E><Name>Microsoft Corporation</Name></Stock></StockQuotes>
My question is how do I extract (for example) the PercentageChange result?
Thank you!
Related
[RESOLVED]
I have a C# program which interfaces with ColdFusion by running a CFM file.
One of the tasks of the CFM file is to create three datasources in ColdFusion. This works well.
The issue I am dealing with is that I have a requirement to use the same methodology in order to delete a datasource. According to Adobe's documentation this function is available, but I cannot find any examples of this on the WWW.
Can anyone here guide me as to how to remove a ColdFusion datasource using code within a CFM file?
Thanks in advance.
Regards,
Ken.
As pointed out by Alex, I really should have included the ColdFusion version number. Version 11.
The working resolution inspired by Ageax's answer is:
<cfscript>
adminObj = createObject("component","cfide.adminapi.administrator");
adminObj.login("#URL.cfpw#");
myObj = createObject("component","cfide.adminapi.datasource");
myObj.deleteDatasource("#URL.ds#");
</cfscript>
I have posed my code here, only because this is the code I actually used and tested.
You can programmatically call the CF Admin API. I believe you can do something like this inside a ColdFusion file.
<cfscript>
/* Connect to CF Admin API */
dbConnection = CreateObject("cfide.adminapi.administrator").login("adminPW","adminUser");
if (dbConnection) {
/* Instantiate datasource object */
ds = createObject("cfide.adminapi.datasource");
/* Delete the datasource */
ds.deleteDatasource("myDatasourceName");
}
</cfscript>
Note: I don't currently have a CF server that I can test on, so please double-check me.
So I'm very new to SOAP and I am trying to connect to the National Weather Service's SOAP service in order to pull forecast data to display on my webpage. Here is my short code for this process:
<cfinvoke
webservice="http://graphical.weather.gov/xml/SOAP_server/ndfdXMLserver.php?wsdl"
method="NDFDgen"
returnvariable="aTemp">
<cfinvokeargument name="latitude" value="37.94"></cfinvokeargument>
<cfinvokeargument name="longitude" value="-75.47"></cfinvokeargument>
<cfinvokeargument name="product" value='"glance"'></cfinvokeargument>
<cfinvokeargument name="startTime" value="2014-05-02T12:00"></cfinvokeargument>
<cfinvokeargument name="endTime" value="2014-05-05T12:00"></cfinvokeargument>
<cfinvokeargument name="Unit" value='"e"'></cfinvokeargument>
<cfinvokeargument name="weatherParameters" value="maxt = TRUE"></cfinvokeargument>
</cfinvoke>
The problem is, when I try and run my webpage, I'm getting the following error:
Web service operation NDFDgen with parameters {Unit={"e"},startTime={2014-05-02T12:00},endTime={2014-05-05T12:00},product={"glance"},longitude={-75.47},weatherParameters={maxt = TRUE},latitude={37.94}} cannot be found.
I'm a bit confused since the NDFDgen operation does indeed exist in the WSDL file I am retrieving, and I have addressed all of the required parameters for the NDFDgen operation.
Link to the WSDL file I am trying to use:
http://graphical.weather.gov/xml/SOAP_server/ndfdXMLserver.php?wsdl
Link to the functions page with required parameters:
http://graphical.weather.gov/xml/#use_it
Can anyone see anything wrong with my code? Is it perhaps something with my arguments I'm passing to SOAP? I even tried following the advice of this Stack Overflow question (Consuming ColdFusion webservice - Web service operation with parameters {} cannot be found) and added the
refreshwsdl="yes"
attribute to my <cfinvoke>, but I am still getting the same error.
With complex web services, it is often easier to go the xml + cfhttp route, as Chester suggested. However, to answer your question, there are a few things wrong with the arguments. That is what the error message means. A method by that name may exist, but its signature does not match the values you have supplied. There is either mismatch in the number of arguments, or in this case, the type of arguments.
According to the wsdl, the start/endTime values must be dates. While CF can implicitly convert a variety of U.S. date strings, it cannot parse the format you are using: yyyy-MM-ddThh:mm. So either use date objects, or use "parseable", date strings such as yyyy-MM-dd hh:mm:ss.
The "weatherParameters" argument should be structure (or complex type) not a string:
<cfset weather = {maxt=true}>
...
<cfinvokeargument name="weatherParameters" value="#weather#">
The Product and Unit values have too many quotes. By using value='"glance"' you are actually including the double quotes as part of the value. That will probably cause an error because the remote web service expects to receive glance (no quotes).
While it will not cause an error, you do not need to include closing tags: </cfinvokeargument>. If you prefer to close it, it is cleaner to use the shortcut <cfinvokeargument ... />
With those changes, your call should work as expected. Though you might want to consider switching to createObject, rather than cfinvoke. Then you can dump the web service object for debugging purposes. It is also less bulky IMO.
<cfscript>
ws = createObject("webservice", "http://graphical.weather.gov/xml/SOAP_server/ndfdXMLserver.php?wsdl");
//show web service methods for debugging purposes
writeDump(ws);
// construct arguments
args = {latitude="37.94"
, longitude="-75.47"
, product="glance"
, startTime="2014-05-02 12:00:00"
, endTime="2014-05-05 12:00:00"
, Unit="e"
, weatherParameters={maxt=true}
};
// call the method
result = ws.NDFDgen(argumentCollection=args);
writeDump(result)
</cfscript>
When you add a debug IP to review the debug information from the collection of templates that are parsed to present the page, it includes a list of all queries from that page.
Is it possible to get access to that object for inspection?
I'm looking at trying to automate the documentation which data sources are in use for which page requests. We have a large number of small web apps that access different databases and have different dependencies. I'm hoping to find a way to automate the documentation of these dependencies rather than having to manually review all code for all of the webapps.
Not sure if the object doesn't get created until after the page creation is too far gone to actually do anything with the data, but who knows...
Here is a snippet of code that you can add to the end of your template to get a list of datasources used on the page:
<cfobject action="CREATE" type="JAVA" class="coldfusion.server.ServiceFactory" name="factory">
<cfset cfdebugger = factory.getDebuggingService()>
<cfset qEvents = cfdebugger.getDebugger().getData()>
<cftry>
<cfquery dbtype="query" name="cfdebug_qryDSN">
SELECT DISTINCT DATASOURCE FROM qEvents WHERE type = 'SqlQuery'
</cfquery>
<cfcatch type="Any">
<cfset cfdebug_qryDSN = queryNew('DATASOURCE')>
</cfcatch>
</cftry>
<cfdump var="#cfdebug_qryDSN#" label="cfdebug_qryDSN">
PS: most of the inspiration for this snippet came from {cfusion 10 home}\cfusion\wwwroot\WEB-INF\debug\classic.cfm. You can get some good ideas on how to gain access to debugger objects/data from this file.
For anyone stumbling across this....
If your [cfroot]/cfusion/lib/neo-datasource.xml file is WDDX encoded and you're not sandboxed, you can use the following (tested on CF2021)
<cflock type="readonly" scope="Server" timeout="5">
<CFSET LibPath=Server.System.Properties["coldfusion.libPath"]>
</cflock>
<CFFILE action="Read" file="#LibPath#/neo-datasource.xml" variable="DatasourcesWDDX">
<cfwddx action="wddx2cfml" input="#DatasourcesWDDX#" output="Datasources">
<cfoutput>#StructKeyList(Datasources[1])#</cfoutput>
<cfdump var=#Datasources#>
The first position of the Datasources array holds a structure containing information on each configured datasource with the main key being the name of the datasource.
Here's an idea that'll work for each application which uses an Application.cfc.
Enable Request Debugging Output in CF Administrator.
Configure Debugging IP Addresses so that every page receives debugging information.
Assuming that Select Debugging Output Format is set to classic.cfm, short circuit {cfusion 10 home}\cfusion\wwwroot\WEB-INF\debug\classic.cfm by making <cfreturn> the first executable statement in classic.cfm. This will prevent any pages from seeing the debug output.
In Application.cfc::OnRequestEnd() do what Scott Jibben suggested. You can wrap Scott's idea in an <cfif IsDebugMode()>.
We have four different environments: dev, q/a, test and prod. I decided to convert our Application.cfm to Application.cfc and put them in our source control. There are plenty application vars that have different values for each environment.
I ended up creating several sql server tables to store these environment variables based on their types. Now, I am in the middle of dynamically setting up these application variables.
My question is that I started adding custom methods inside application.cfc. I am not 100% sure if this is the best place. [For example: getAppLinks(), setAppLinks() ]. Otherwise, I could create a new cfc and call this one from Application.cfc.
All these methods are currently being called once in the onApplicationStart() method.
Does anybody have any comments on implementing custom methods in Application.cfc?
thanks
edited: added a custom method:
<cffunction name="setUpAppDSNs" access="private" returnType="void" output="false">
<cfargument name="dsn" type="string" required="yes">
<cfargument name="serverName" type="string" required="yes">
<cfscript>
var dsnNames = structNew();
var qryAppDSNs = new Query(dataSource = '#arguments.dsn#',
sql = ' SELECT dsnID, #arguments.serverName#Server, description
FROM cfAppDSN ').execute().getResult();
for (i = 1; i lte qryAppDSNs.recordCount; i++) {
dsnNames['#qryAppDSNs.description[i]#'] = qryAppDSNs['#serverName#Server'][i];
}
StructAppend(application,dsnNames);
</cfscript>
</cffunction>
I have a similar issue and solved it by extending the application.cfc with our globalFunctions.cfc
<cfcomponent displayname="Application"
output="false" extends="shared.cfc.globalFunctions">
I don't know if this will work for you but it allowed us to use the same functions it multiple different applications without maintaining multiple copies of those functions.
Application.cfc is just a CFC. the only "special" things about it are:
CF instantiates an instance of it every request;
coincidental to that, ColdFusion looks for a few event handlers and interceptors in there (onApplicationStart(), etc).
But it's still just a CFC. Given it's called Application.cfc and busies itself with the application lifecycle, it makes sense to put methods in there that relate to the application lifecycle - same as with organising any CFC.
So to answer your question... Application.cfc is exactly the right place for these methods of yours.
The host that I want to host with does not support server side url rewriting, thus no third party tools can be installed to rewrite the url's.
This is Coldfusion 8, on windows, IIS.
The other alternative that I know of is to use a framework, but I do not feel like taking that route (time), for the application works well as it is (but the URL).
Can clean urls be generated by purely CF?
I do not need the clean url's for seo, rather it will be for the user's easy reference to their page. E.g. youtube.com/userpage
Any sugessions?
If the only choice is to use a framework, then which one is most compatible with traditional cfml'', cfm's & CFC's? In that there needs to be minimum changes to the code in the conversion from the none frameworked app to become frameworked.
Thanks for you contributions!
No. you do not need a framework or URL rewriter to get http://domain.com/some/url to work (notice no index.cfm).
In IIS you can set up custom error pages for 404 errors. Make the custom error page execute a ColdFusion page on your server (/urlhandler.cfm, 404.cfm or index.cfm for example). Within that page, you can control your own routes with ColdFusion by using list methods on the cgi.query_string value. IIS will provide you a url that looks something like 404;http://domain.com/the/original/url which you can parse to route the visitor to your desired event.
<!--- Get URL String --->
<cfset CurrentURL = ListGetAt(cgi.query_string, 2, ";")>
<cfset CurrentURL = Replace(CurrentURL, ":80", "")>
<cfset CurrentURL = Replace(CurrentURL, ":443", "")>
<cfset CurrentURL = Replace(CurrentURL, "403;", "")>
<cfset CurrentURL = Replace(CurrentURL, "'", "", "ALL")>
We have a site that receives approx a million visitors a month that is still running SES urls with this method. I was shocked when I was hired and found this existing code at the heart of the site and would not elect to repeat it, but, if you have limitations on installing a rewriter or third party framework (this client placed restrictions on the site) this solution may work for you.
By playing with the above code, you can quickly see how you may use CF to dynamically include the .CFM file you want or execute the right CFC code depending on your set up.
You can use the Framework/1 framework or CFWheels to achieve clean URL's but it will need to include the "/index.cfm/" at the beginning of the URL in order to trigger ColdFusion's application handler code.
EDIT: Please see Aaron Greenlee's work around to prevent the "index.cfm" from appearing in the URL.
i.e. Whichever approach you take, if you cannot add a 3rd party tool to rewrite URLs (and not using Apache), your URL's will be in the form of http://site.com/index.cfm/section/item
eg.
http://site.com/index.cfm/user/login
http://site.cfm/index.cfm/user/signup
FW/1 offers the option of passing in URL variables in a search engine friendly format as well.
Examples:
http://site.com/index.cfm/user/login/email/me#you.com/password/test
is the same as
http://site.com/index.cfm/user/login?email=me#you.com&password=test
is the same as
http://site.com/index.cfm?action=user.login&email=me#you.com&password=test
Go ahead and learn a framework. Most will work for this. However if you just do not want to learn a framework.
www.mysite.com/products/
will run:
www.mysite.com/products/index.cfm
www.mysite.com/products/books
will run:
www.mysite.com/products/books/index.cfm
Framework/1 and CFZen will work for this a they are very simple 1 file frameworks that you can just work around.
CFZen
http://cfzen.riaforge.org
http://cftipsplus.com/blog/?tag=cfzen
Framework/1
http://fw1.riaforge.org
http://corfield.org - the author of Framework/1
Instead of using http://yoursite.com/index.cfm/user, you can do http://yoursite.com/user.cfm and catch the error in the OnMissingTemplate function of application.cfc. This will not require you to set a custom 404 page.