cfxml vs cfsavecontent - unable to build xml using cfxml - coldfusion

I'm trying build a custom XML file and splitting the building into separate functions, but I'm having trouble doing this with cfxml. This example is obviously simplified.
This works fine:
<cfcomponent accessors="true">
<cfproperty name="Name" />
<cfproperty name="Model" />
<cfproperty name="Make" />
<cffunction name="BuildCarXML" output="false">
<cfsavecontent variable="xmlCar">
<cfoutput>
<?xml version="1.0" encoding="UTF-8" ?>
<car>
<name>#variables.Name#</name>
#AddMakeElement()#
</car>
</cfoutput>
</cfsavecontent>
<cfreturn xmlCar />
</cffunction>
<cffunction name="AddMakeElement">
<cfsavecontent variable="xmlMake">
<cfoutput>
<make>Something</make>
</cfoutput>
</cfsavecontent>
<cfreturn xmlMake />
</cffunction>
</cfcomponent>
But this produces an XML string with spaces:
<?xml version="1.0" encoding="UTF-8" ?> <car> <name>Ferrari</name> <make>Something</make> </car>
If I use cfxml, or even do an XMLParse() on the cfreturn of BuildCarXML, i get the following error:
An error occured while Parsing an XML document.
The processing instruction target matching "[xX][mM][lL]" is not allowed.
Is it possible to do this using cfxml?

In AddMakeElement(), if you use <cfxml> and toString(), the output is:
<?xml version="1.0" encoding="UTF-8"?> <make>Something</make>
Therefore it couldn't be embedded into your xmlCar. So for AddMakeElement(), keep using <cfsavecontent>, or just return "<make>Something</make>".

Related

Twilio inbound SMS using webhooks and Coldfusion

I have setup SMS on Twilio and can receive an SMS via webhooks. I can manipulate the form data to do what I want however every inbound SMS message throws an error on Twilio's dashboard. It's looking for some response. Right now I'm just dumping the form to a text file while testing.
<!doctype html>
<?xml version="1.0" encoding="UTF-8"?>
<html>
<head>
<Response>
</Response>
<cfdump
var="#form#"
label="HTTP Body" output="C:/webhook-sms.txt"
/>
</head>
</html>
The error is: MESSAGE
The markup in the document preceding the root element must be well-formed.
Warning - 12200
Schema validation warning
The provided XML does not conform to the Twilio Markup XML schema. Please refer to the specific error and correct the problem.
What do I need to respond to Twilio with?
Thanks in advance for any help!
Gary
Twilio expects a content type of text/xml and also expects the first line of the response to be <?xml version="1.0" encoding="UTF-8"?>.
If your response has one or more empty lines before <?xml version="1.0" encoding="UTF-8"?> you're still going to get an error.
What I ended up doing, was with an Application.cfm something like this:
<cfsetting enablecfoutputonly="true" showdebugoutput="false" requesttimeout="30" />
<cfheader name="content-type" value="text/xml" />
<!--- // more code --->
and endpoint files which start with the first line like this:
<cfoutput><?xml version="1.0" encoding="UTF-8"?></cfoutput>
<!--- // more code --->
And make sure you send back valid TwiML (Twilio's XML) (no HTML).
Thanks everybody. My final test code looked like this:
<cfsetting enablecfoutputonly="true" showdebugoutput="false" requesttimeout="30" />
<cfheader name="content-type" value="text/xml" />
<cfoutput><?xml version="1.0" encoding="UTF-8"?>
<Response>
<Message>Thanks for getting in touch, I'll call you later</Message>
</Response></cfoutput>

Coldfusion - Creating SOAP Web Service

Here is the XML format that I'm trying to create a web service for:
<test a1="a1">
<e1>e1</e1>
<e2 a2="a2">
<e3>e3</e3>
<e3>e3</e3>
</e2>
</test>
My problem is that I don't know how to create a Coldfusion (cfcomponent) SOAP web service that would conform to the XML format.
This is what I have come up with:
<cfcomponent style="document" wsversion = 1 >
<cffunction name="test" returntype="String" access="remote">
<cfargument type="String" required="no" name="e1"/>
<cfargument type="xml" required="no" name="e2" />
<cfreturn "ok">
</cffunction>
</cfcomponent>
As you can see, a1,a2 and e3 are left out as I have no idea how to define them in the cffunction, and I'm not sure if making e2 as xml type is correct.
Any help is appreciated.
you have to use
<cfsavecontent variable="textxml">
<cfoutput>
<test a1="a1">
<e1>e1</e1>
<e2 a2="a2">
<e3>e3</e3>
<e3>e3</e3>
</e2>
</test>
</cfoutput>
</cfsavecontent>
and pass the testxml variable to the function as xml type argument.
<cfinvoke method="test" component="compname" xmltest="#textxml#">
no need to send seperate arguments e1 e2...can send testxml variable to the function.
<cfcomponent >
<cffunction name="test" returntype="String" access="remote">
<cfargument type="xml" required="no" name="xmltest" />
<cfset newXML = XMLParse(arguments.xmltest)>
<cfdump var="#newXML#">
<cfreturn "ok">
</cffunction>
</cfcomponent>

API Consumption Coldfusion

I am trying to consume an api and trying to convert this code to codfusion
<?php
$client = new SoapClient(
"http://trial.black011.com/retailer/Black011SvcDemo.wsdl”,
array( "trace" => 1,
"exceptions" => 0)
);
try {
$arr = $client->recharge( ‘TestID, "TestPassword", "BKLD", “1234567890”,
10, "Any Comment1 of You" );
echo 'error_code' . $arr['error_code'];
echo 'error_msg' . $arr['error_msg'];
echo 'tx_id' . $arr['tx_id'];
echo 'comment1' . $arr['comment1'];
}catch (SoapFault $exception) {
echo "Error Code:" . $exception->getCode();
echo "Error Message:" . $exception->getMessage();
}
?>
I am using below code to consume the api
<cfinvoke webservice="http://trial.black011.com/retailer/Black011SvcDemo.wsdl" method="recharge" returnvariable="res" refreshwsdl="true" >
<cfinvokeargument name="user_id" value="TestID">
<cfinvokeargument name="passwd" value="TestPassword">
<cfinvokeargument name="prod_id" value="BKLD">
<cfinvokeargument name="mdn" value="1112223333">
<cfinvokeargument name="amount" value="10">
<cfinvokeargument name="comment1" value="10">
</cfinvoke>
I also tried this-
<cfscript>
ws = createObject("webservice", "http://trial.black011.com/retailer/Black011SvcDemo.wsdl");
writeDump(ws);
result = ws.recharge( "TestID", "TestPassword", "BKLD", "19112223333", 10.00 );
writeDump(result);
</cfscript>
But every time I am trying, getting below error-
Web service operation recharge with parameters {} can not be found.
Could anybody see any problem with my code?
I have a code and seems to be working as I tested it.
<cfsavecontent variable="soapBody">
<cfoutput>
<?xml version="1.0" encoding="utf-8"?>
<soapenv:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:urn="urn:black011">
<soapenv:Header/>
<soapenv:Body>
<urn:recharge soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<user_id xsi:type="xsd:string">test</user_id>
<passwd xsi:type="xsd:string">twawd</passwd>
<prod_id xsi:type="xsd:string">"BKLD"</prod_id>
<mdn xsi:type="xsd:string">"1234567890"</mdn>
<amount xsi:type="xsd:float">20.0</amount>
<comment1 xsi:type="xsd:string">"test"</comment1>
</urn:recharge>
</soapenv:Body>
</soapenv:Envelope>
</cfoutput>
</cfsavecontent>
<cfhttp url="http://trial.black011.com/retailer/OpenSvc.php" method="post" result="httpResponse">
<cfhttpparam type="header" name="SOAPAction" value="http://trial.black011.com/retailer/OpenSvc.php/recharge" />
<cfhttpparam type="header" name="accept-encoding" value="no-compression" />
<cfhttpparam type="xml" value="#trim( soapBody )#" />
</cfhttp>
<cfif find( "200", httpResponse.statusCode )>
<cfset soapResponse = xmlParse( httpResponse.fileContent ) />
<cfdump var="#soapResponse#">
</cfif>
Look at ws variable dump, method recharge takes 9 parameters:
recharge(java.lang.String,
java.lang.String,
java.lang.String,
java.lang.String,
float,
javax.xml.rpc.holders.StringHolder,
javax.xml.rpc.holders.StringHolder,
javax.xml.rpc.holders.StringHolder,
javax.xml.rpc.holders.StringHolder) returns void
Seems the code below works fine:
<cfscript>
wsargs = {};
wsargs.refreshwsdl = "Yes";
ws = createObject("webservice",
"http://trial.black011.com/retailer/Black011SvcDemo.wsdl",
wsargs);
result = ws.recharge("TestID",
"TestPassword",
"BKLD",
"19112223333",
10.0,
"test",
"test",
"test",
"test");
</cfscript>
Hope this could help
In your question you state you are specifing the method as follows
result = ws.recharge( "TestID", "TestPassword", "BKLD", "19112223333", 10.00 );
Which has 5 arguments. The WSDL reads
<message name="rechargeRequest">
<part name="user_id" type="xsd:string"/>
<part name="passwd" type="xsd:string"/>
<part name="prod_id" type="xsd:string"/>
<part name="mdn" type="xsd:string"/>
<part name="amount" type="xsd:float"/>
<part name="comment1" type="xsd:string"/>
</message>
There are 6 arguments. You need to specify something for the 6th arguments, as typically with WSDLs the arguments help define the function in the same way as the function name does. There aren't any optional arguments. This gives the following which should work
result = ws.recharge(
"TestID",
"TestPassword",
"BKLD",
"19112223333",
10.00,
"Some comment here"
);

ColdFusion soap client

The following is a sample SOAP 1.2 request and response. The placeholders shown need to be replaced with actual values.
POST /CommunicationOfficeService1_0/CompanyAccountXmlService.asmx HTTP/1.1
Host: webservices.nbs.rs
Content-Type: application/soap+xml; charset=utf-8
Content-Length: length
<?xml version="1.0" encoding="utf-8"?>
<soap12:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap12="http://www.w3.org/2003/05/soap-envelope">
<soap12:Header>
<AuthenticationHeader xmlns="http://communicationoffice.nbs.rs">
<UserName>string</UserName>
<Password>string</Password>
<LicenceID>guid</LicenceID>
</AuthenticationHeader>
</soap12:Header>
<soap12:Body>
<GetCompanyAccountByNationalIdentificationNumber xmlns="http://communicationoffice.nbs.rs">
<nationalIdentificationNumber>long</nationalIdentificationNumber>
</GetCompanyAccountByNationalIdentificationNumber>
</soap12:Body>
</soap12:Envelope>
HTTP/1.1 200 OK
Content-Type: application/soap+xml; charset=utf-8
Content-Length: length
<?xml version="1.0" encoding="utf-8"?>
<soap12:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap12="http://www.w3.org/2003/05/soap-envelope">
<soap12:Body>
<GetCompanyAccountByNationalIdentificationNumberResponse xmlns="http://communicationoffice.nbs.rs">
<GetCompanyAccountByNationalIdentificationNumberResult>string</GetCompanyAccountByNationalIdentificationNumberResult>
</GetCompanyAccountByNationalIdentificationNumberResponse>
</soap12:Body>
</soap12:Envelope>
I have generated the ColdFusion code that looks like this
<cfsavecontent variable="soapBody">
<cfoutput>
POST /CommunicationOfficeService1_0/CompanyAccountXmlService.asmx HTTP/1.1
Host: webservices.nbs.rs
Content-Type: application/soap+xml; charset=utf-8
Content-Length: length
<?xml version="1.0" encoding="utf-8"?>
<soap12:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap12="http://www.w3.org/2003/05/soap-envelope">
<soap12:Header>
<AuthenticationHeader xmlns="http://communicationoffice.nbs.rs">
<UserName>my_username</UserName>
<Password>my_password</Password>
<LicenceID>My_licence_id</LicenceID>
</AuthenticationHeader>
</soap12:Header>
<soap12:Body>
<GetCompanyAccountByNationalIdentificationNumber xmlns="http://communicationoffice.nbs.rs">
<nationalIdentificationNumber>20774550</nationalIdentificationNumber>
</GetCompanyAccountByNationalIdentificationNumber>
</soap12:Body>
</soap12:Envelope>
</cfoutput>
</cfsavecontent>
<!---
Now that we have our SOAP body defined, we need to post it as
a SOAP request to the Campaign Monitor website. Notice that
when I POST the SOAP request, I am NOT required to append the
"WSDL" flag to the target URL (this is only required when you
actually want to get the web service definition).
--->
<cfhttp
url="https://webservices.nbs.rs/CommunicationOfficeService1_0/CompanyAccountXmlService.asmx"
method="post"
result="httpResponse">
<!---
Most SOAP action require some sort of SOAP Action header
to be used.
--->
<cfhttpparam
type="header"
name="SOAPAction"
value="http://communicationoffice.nbs.rs/GetCompanyAccountByNationalIdentificationNumber"
/>
<!---
I typically use this header because CHTTP cannot handle
GZIP encoding. This "no-compression" directive tells the
server not to pass back GZIPed content.
--->
<cfhttpparam
type="header"
name="accept-encoding"
value="no-compression"
/>
<!---
When posting the SOAP body, I use the CFHTTPParam type of
XML. This does two things: it posts the XML as a the BODY
and sets the mime-type to be XML.
NOTE: Be sure to Trim() your XML since XML data cannot be
parsed with leading whitespace.
--->
<cfhttpparam
type="xml"
value="#trim( soapBody )#"
/>
</cfhttp>
<!---
When the HTTP response comes back, our SOAP response will be
in the FileContent atribute. SOAP always returns valid XML,
even if there was an error (assuming the error was NOT in the
communication, but rather in the data).
--->
<cfif find( "200", httpResponse.statusCode )>
<!--- Parse the XML SOAP response. --->
<cfset soapResponse = xmlParse( httpResponse.fileContent ) />
<!---
Query for the response nodes using XPath. Because the
SOAP XML document has name spaces, querying the document
becomes a little funky. Rather than accessing the node
name directly, we have to use its local-name().
--->
<cfset responseNodes = xmlSearch(
soapResponse,
"//*[ local-name() = 'Subscriber.AddAndResubscribeResult' ]"
) />
<!---
Once we have the response node, we can use our typical
ColdFusion struct-style XML node access.
--->
<cfoutput>
Code: #responseNodes[ 1 ].Code.xmlText#
<br />
Success: #responseNodes[ 1 ].Message.xmlText#
</cfoutput>
</cfif>
I have none results . The web service uses this is the web site
This is the wsdl file
Serbian National Bank Web Service
How to make this web service run
I've modified a function I've used in the past to pass data form ColdFusion to Dynamics GP via soap.
<cffunction name="callWebService" access="public" output="false">
<cfargument name="soap" type="xml" required="true">
<cfhttp url="https://webservices.nbs.rs/CommunicationOfficeService1_0/CompanyAccountXmlService.asmx" method="post">
<cfhttpparam type="header" name="content-type" value="application/soap+xml">
<cfhttpparam type="header" name="SOAPAction" value="http://communicationoffice.nbs.rs/GetCompanyAccountByNationalIdentificationNumber">
<cfhttpparam type="header" name="accept-encoding" value="no-compression">
<cfhttpparam type="header" name="content-length" value="#len(Arguments.soap)#">
<cfhttpparam type="header" name="charset" value="utf-8">
<cfhttpparam type="xml" name="message" value="#trim(Arguments.soap)#">
</cfhttp>
<cfreturn Trim(cfhttp.FileContent)>
</cffunction>
I believe I've updated the <cfhttpparam />s necessary for the web service you've linked. I would recommend using a software called SOAP UI to test your connection to the service and SOAP XML body outside of ColdFusion. In my above function, the argument soap would be your saved content "soapBody".
One thing needs to be fixed in your soapBody. The text prior to the start of XML is information regarding data that needs to be in the HTTP header, and I've only seen these values imputed as <cfhttpparam />.
The reason I think you may not be getting the desired 200 response with your above code is that the XML body is incorrectly formatted with the WSDL HTTP header example text. I also did not see the length of the body being declared as well.
While trying to set up your connection try just dumping httpResponse out until you start seeing valid soap responses from the server.

Consuming ColdFusion RESTful Service

I created a Rest Service with ColdFusion. It returns an xml file or json like this:
<query id ='1'>
<columnnames>
<COLUMN NAME="Name">
<COLUMN NAME="Surname">
</columnnames>
<ROW>
<COLUMN TYPE="STRING">...</COLUMN>
<COLUMN TYPE="STRING">...</COLUMN>
</ROW>
or
{"COLUMNS":["Name","Surname"],"DATA":[["...","..."]
Is there anyone that can explain how I can parse this data into a grid with ExtJS or another javascript framework?
This is my cfc:
<cfcomponent rest="true" restpath="/hello">
<cffunction name="query" returntype="query" access="remote" produces="application/json" httpmethod="GET">
<cfquery name="myQuery" datasource="dbrc">
SELECT Name, Surname
FROM TBUSERS
LIMIT 10
</cfquery>
<cfreturn myQuery>
</cffunction>
</cfcomponent>
Thanks and sorry for my English.
Have you looked using at the JSONReader in extjs or jQuery.getJSON function?
NOTE :
Despite the fact that the web service was created using ColdFusion, this is a javascript/ext.js question and not a ColdFusion question.
returntype="any" produces="application/json"
in the api cfcomponent is what I used to return the query results in json format
<cfcomponent rest="true" restpath="restService" produces="application/json">
I can't tell if returnformat="JSON" in the cffunction tag does anything for the api being returned in json.
<cffunction name="test" access="remote" returnformat="JSON" returntype="any" httpmethod="GET" >