Grails/Groovy problem with XmlSlurper .. help - grails

Using grails 1.2.2 with groovy 1.6.8 .. Reading a a web service and trying to process response ..
Response is shown below and validates as correct xml .. (sorry for length) ..
<soap:Body>
<AddProductEventResponse xmlns="http://tempuri.org/">
<AddProductEventResult>
<xs:schema id="AddProductEventResult" xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xs:element name="AddProductEventResult" msdata:IsDataSet="true" msdata:UseCurrentLocale="true">
<xs:complexType>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="AddProductEventResult">
<xs:complexType>
<xs:sequence>
<xs:element name="ErrorCode" type="xs:string" minOccurs="0"/>
<xs:element name="ErrorNumber" type="xs:int" minOccurs="0"/>
<xs:element name="ErrorDesc" type="xs:string" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:choice>
</xs:complexType>
</xs:element>
</xs:schema>
<diffgr:diffgram xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" xmlns:diffgr="urn:schemas-microsoft-com:xml-diffgram-v1">
<AddProductEventResult xmlns="">
<AddProductEventResult diffgr:id="AddProductEventResult1" msdata:rowOrder="0" diffgr:hasChanges="inserted">
<ErrorCode>S</ErrorCode>
<ErrorNumber>0</ErrorNumber>
<ErrorDesc>Success</ErrorDesc>
</AddProductEventResult>
</AddProductEventResult>
</diffgr:diffgram>
</AddProductEventResult>
</AddProductEventResponse>
</soap:Body>
</soap:Envelope>
I try to parse this using
def myXml = new XmlSlurper().parseText(result)
where result is the above message and i get an error ...
2010-06-19 06:08:03,665 [http-8080-2] ERROR errors.GrailsExceptionResolver - Premature end of file.
org.xml.sax.SAXParseException: Premature end of file.
at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(AbstractSAXParser.java:1231)
at com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser.parse(SAXParserImpl.java:522)
which is the above xmlSlurper statement ..
If i copy and run from groovyConsole i don't have the problem .. I created a stripped down Grails project
and ran it from there without problems either .. I'm getting a little bit desperate to get this sorted (have posted on Grails site to) so has anyone any idea ?

The above shown XML document cannot be validated. There is an ending tag </soap:Envelope> but no according start tag. Are you sure you are providing the complete XML here?
This works without any parsing exception:
<?xml version="1.0"?>
<soap:Envelope xmlns:soap="http://www.w3.org/2001/12/soap-envelope" soap:encodingStyle="http://www.w3.org/2001/12/soap-encoding">
<soap:Body>
<AddProductEventResponse xmlns="http://tempuri.org/">
<AddProductEventResult>
<xs:schema id="AddProductEventResult" xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xs:element name="AddProductEventResult" msdata:IsDataSet="true" msdata:UseCurrentLocale="true">
<xs:complexType>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="AddProductEventResult">
<xs:complexType>
<xs:sequence>
<xs:element name="ErrorCode" type="xs:string" minOccurs="0"/>
<xs:element name="ErrorNumber" type="xs:int" minOccurs="0"/>
<xs:element name="ErrorDesc" type="xs:string" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:choice>
</xs:complexType>
</xs:element>
</xs:schema>
<diffgr:diffgram xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" xmlns:diffgr="urn:schemas-microsoft-com:xml-diffgram-v1">
<AddProductEventResult xmlns="">
<AddProductEventResult diffgr:id="AddProductEventResult1" msdata:rowOrder="0" diffgr:hasChanges="inserted">
<ErrorCode>S</ErrorCode>
<ErrorNumber>0</ErrorNumber>
<ErrorDesc>Success</ErrorDesc>
</AddProductEventResult>
</AddProductEventResult>
</diffgr:diffgram>
</AddProductEventResult>
</AddProductEventResponse>
</soap:Body>
</soap:Envelope>

Forgive me , i missed first line off by accident .. should have had
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" mlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
as first line ..
Problem still remains BUT i've traced the error to something which looks really inoccuous ..
In a controller i have ..
def result = myService.productListService()
if (result != "Error") {
def xml = new XmlSlurper().parseText(result)
which throws my original error. In my service i have ..
def productListService() {
....
def someList = processRequest(conn, msgBody, "Products")
return someList
....
}
and a helper method ..
// Helper routines ..
String processRequest(conn, dataString, serviceName) {
conn.setRequestMethod("POST")
conn.doOutput = true
Writer writer = new OutputStreamWriter(conn.outputStream)
writer.write(dataString)
writer.flush()
writer.close()
conn.connect()
if (conn.responseCode == 200 || conn.responseCode == 201){
println "Response .. "
println conn.content.text <--------- Remove this and problem goes away !!!
return conn.content.text
}
println serviceName + " FAILED .. "
println conn.responseCode
println conn.responseMessage
return "Error"
}
The xml is the conn.content.text variable and my helper routine echoes it to the screen for testing. It also has the unfortunate side effect of being the cause of my problem ! Without the outputing of the line everything works fine , with it i get the aforementioned xmlSlurper error .. very strange (to me at least) .. I don't understand that ..

I'm assuming your conn.content is an InputStream. According to the GDK documentation getText() will consume and close the stream. Calling it twice would thus most likely either throw an exception or return an empty string.

Related

Create output Xml file from XML and XSD using DataSet

I've got two example files: note.xml and note.xsd. I would like to combine this two files using DataSet and create output XML file, based on this operation. How can i do it?
note.xml
<?xml version="1.0"?>
<note>
<to>Tove</to>
<from>Jani</from>
<heading>Reminder</heading>
<body>Don't forget me this weekend!</body>
</note>
note.xsd
<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="https://www.w3schools.com"
xmlns="https://www.w3schools.com"
elementFormDefault="qualified">
<xs:element name="note">
<xs:complexType>
<xs:sequence>
<xs:element name="to" type="xs:string"/>
<xs:element name="from" type="xs:string"/>
<xs:element name="heading" type="xs:string"/>
<xs:element name="body" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
UPDATE
Basically, i would like to combine XSD and XML and create output XML file. I want to use something like data table relations(DataSet)
Then after combine, we can decide based on data type(string, int..), which for example: dataform can store this.

Biztalk 2010 : Not able to Query SalesForece through Enterprise WSDL.Illegal Header issue

I am implementing BizTalk 2010 Saleforce integration where I am purely using enterprise wsdl for calling its methods. No C# code for any operation.
I am successfully able to call login method and getting result back with all details. Now at the subsequent request where I am calling query method which does not take additional parameter for taking header. It is only taking query string as parameter shown below.
<element name='query'>
<complexType>
<sequence>
<element name='queryString' type='string' />
</sequence>
</complexType>
</element>
Now the problem is when I am calling this method it is giving me error for "Invalid Session and Illegal Session Header" because no header getting passed.
Alternative that I tried is constructing message and passing header with session id (taking from login result) explicitly as shown below.
Option 1.
varXMLDocument = new System.Xml.XmlDocument();
varXMLDocument.LoadXml("<ns0:Envelope xmlns:ns0='http://QuerySFDCVIAWSDL.QueryRequestSchema'><Body><query><queryString>SELECT "some fields xyz..." FROM Quote</queryString></query></Body></ns0:Envelope>");
msgSendQryToSalesforce = varXMLDocument;
//Setting Header
msgSendQryToSalesforce(WCF.Headers) = "<ns0:SessionHeader xmlns:ns0=\"urn:enterprise.soap.sforce.com\"><ns0:sessionId>" + SessionId + "</ns0:sessionId></ns0:SessionHeader>";
Option 2.
//Creating session header in same xml.
varXMLDocument.LoadXml("<ns0:Envelope xmlns:ns0='http://QuerySFDCVIAWSDL.QueryRequestSchema'><Header><SessionHeader><sessionId>"+SessionId+"</sessionId></SessionHeader></Header><Body><query><queryString>SELECT "some fields xyz..." FROM Quote</queryString></query></Body></ns0:Envelope>");
The problem with these approach is SessionHeader getting removed at runtime and only querystring getting passed to SFDC. Hence getting same result "Invalid Session and Illegal Session Header".
//Request From Orchestration Debugger where there is no session header after been passed explicitly, it is only taking querystring.
//Final Request
<ns0:query xmlns:ns1="urn:sobject.enterprise.soap.sforce.com" xmlns:ns0="urn:enterprise.soap.sforce.com"><ns0:queryString>SELECT "some fields xyz..." FROM Quote</ns0:queryString></ns0:query>
Can anybody please help me and assist me in finding out the appropriate solution so that at all subsequent request have session ids passed in session header.
From SoapUI tool when I am passing same xml with session header it is getting me result back.
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:urn="urn:enterprise.soap.sforce.com">
<soapenv:Header>
<urn:SessionHeader> <urn:sessionId>some id.......</urn:sessionId>
</urn:SessionHeader>
</soapenv:Header>
<soapenv:Body>
<urn:query>
<urn:queryString>Select "some fields xyz..." from Quote</urn:queryString>
</urn:query>
</soapenv:Body>
</soapenv:Envelope>
Not able to understand why from BizTalk it is not working.
Just FYI my queryRequestSchema
Just FYI my queryRequestSchema
<?xml version="1.0"?>
<xs:schema targetNamespace="http://QuerySFDCVIAWSDL.QueryRequestSchema" xmlns="http://QuerySFDCVIAWSDL.QueryRequestSchema" xmlns:b="http://schemas.microsoft.com/BizTalk/2003" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="Envelope">
<xs:complexType>
<xs:sequence>
<xs:element name="Header">
<xs:complexType>
<xs:sequence>
<xs:element name="SessionHeader">
<xs:complexType>
<xs:sequence>
<xs:element name="sessionId" type="xs:string"></xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="Body">
<xs:complexType>
<xs:sequence>
<xs:element name="query">
<xs:complexType>
<xs:sequence>
<xs:element name="queryString" type="xs:string"></xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
Thanks in Advance.
Use the (WCF.CustomOutboundHeaders) context property.
Replace this line:
//Setting Header
msgSendQryToSalesforce(WCF.Headers) = "<ns0:SessionHeader xmlns:ns0=\"urn:enterprise.soap.sforce.com\"><ns0:sessionId>" + SessionId + "</ns0:sessionId></ns0:SessionHeader>";
With this
// Setting Header
msgSendQryToSalesforce(WCF.OutboundCustomHeaders) = "<ns0:SessionHeader xmlns:ns0=\"urn:enterprise.soap.sforce.com\"><ns0:sessionId>" + SessionId + "</ns0:sessionId></ns0:SessionHeader>";
If you're using a utilities class, it might be a good idea to store that header template in a public const string variable, or write a method to format it for you - assuming you'll be sending multiple messages to Salesforce, you'll be able to reuse it more easily:
msgSendQryToSalesforce(WCF.OutboundCustomHeaders) = Utilities.GetSalesforceHeader(SessionId);
and in your utilities class, have a method like
public static string GetSalesforceHeader(string sessionId)
{
return "<ns0:SessionHeader xmlns:ns0=\"urn:enterprise.soap.sforce.com\"><ns0:sessionId>" + sessionId + "</ns0:sessionId></ns0:SessionHeader>";
}
More information on setting SOAP headers in Orchestrations:
https://msdn.microsoft.com/en-us/library/bb246026.aspx (but note that you don't actually have to use an XmlDocument for this); this applies to 2010 even though it says its for 2013.

Invalid Content Was Found Starting With Element 'country'. One Of '{country}' Is Expected.. Line '10', Column '14'

I am trying to resolve this issue but could not understand the root cause of this error:
Invalid Content Was Found Starting With Element 'country'. One Of '{country}' Is Expected.. Line '10', Column '14'
Here is my xml:
<?xml version="1.0"?>
<!--DTD file reference-->
<!--<!DOCTYPE countries SYSTEM "http://localhost:8080/ajaxprac/file.dtd">-->
<!--DTD file reference-->
<!---->
<countries xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://localhost:8080/ajaxprac"
xsi:schemaLocation="http://localhost:8080/ajaxprac fileSchema.xsd">
<country>
<name>pakistan</name>
<cities>
<city>Kassowal</city>
<city>Faisalabad</city>
<city>Multan</city>
</cities>
</country>
<country>
<name>india</name>
<cities>
<city>Agra</city>
<city>Amritsar</city>
<city>Ayodhya</city>
</cities>
</country>
</countries>
and xsd file for this is:
<?xml version="1.0"?>
<!--
To change this template, choose Tools | Templates
and open the template in the editor.
-->
<xs:schema version="1.0"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://localhost:8080/ajaxprac"
xmlns="http://localhost:8080/ajaxprac">
<xs:element name="countries" type="countriesType"/>
<xs:element name="name" type="xs:string"/>
<xs:element name="city" type="xs:string"/>
<xs:complexType name="countriesType">
<xs:sequence>
<xs:element name="country" type="countryType"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="countryType">
<xs:sequence>
<xs:element ref="name"/>
<xs:element name="cities" type="citiesType"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="citiesType">
<xs:sequence>
<xs:element ref="city"/>
</xs:sequence>
</xs:complexType>
</xs:schema>
As written, your schema expects the "global" countries, name and city elements to be in the http://localhost:8080/ajaxprac namespace, but the "local" elements (those declared inside a complexType, i.e. country and cities) to be in no namespace. You probably want to add elementFormDefault="qualified", i.e.
<xs:schema version="1.0"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://localhost:8080/ajaxprac"
xmlns="http://localhost:8080/ajaxprac"
elementFormDefault="qualified">
which applies the targetNamespace to local, as well as global, element declarations.

What does `extra classes` parameter from `Java2WSDL` do?

Does anyone know what extra classes parameter from Java2WSDL tool mean?
Java2DSDL Reference
I am looking to answer this question, but have no success.
It is used to include those types in WSDL definition whose parents appears as return types or parameters. Consider very simple example:
public class DemoService {
public Animal pickRandomAnimal() {
return new Dog(); // or any other animal
}
}
.. where Animal is an interface. At a WSDL generation time Axis2 will not be able to automatically trace all possible implementations of Animal that you might expect to be returned. Without extraClasses you'll get something like this:
<xs:schema attributeFormDefault="qualified" elementFormDefault="qualified" targetNamespace="http://demo.com/xsd">
<xs:complexType name="Animal">
<xs:sequence>
<xs:element minOccurs="0" name="animalName" nillable="true" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:schema>
.. and if you add extraClasses="com.demo.Dog", you'll cover all types you need in your WSDL schema part:
<xs:schema attributeFormDefault="qualified" elementFormDefault="qualified" targetNamespace="http://demo.com/xsd">
<xs:complexType name="Animal">
<xs:sequence>
<xs:element minOccurs="0" name="animalName" nillable="true" type="xs:string"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="Dog">
<xs:sequence>
<xs:element minOccurs="0" name="animalName" nillable="true" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:schema>

Groovy/Grails Using WSClient to consume .net web service

I'm pretty new to both Grails/Groovy/Web services and i'm consuming a .net web service ..
I have some code connects to the service using grails WS-client plugin :
WebService webService
def result = {
def wsdl =
ApplicationHolder.application.parentContext.getResource('WEB-INF/productsSoap.wsdl')
def proxy = webService.getClient(wsdl.getURL().toString())
def productTypeListResponse = proxy.ProductTypeList()
}
I also used soapUI to examine the data returned from the web service which gave ..
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body>
<ProductTypeListResponse xmlns="http://tempuri.org/">
<ProductTypeListResult>
<xs:schema id="ProductTypeListResult" xmlns=""
xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xs:element name="ProductTypeListResult" msdata:IsDataSet="true" msdata:UseCurrentLocale="true">
<xs:complexType>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="ProductTypeListResult">
<xs:complexType>
<xs:sequence>
<xs:element name="PRD_TypeId" type="xs:int" minOccurs="0"/>
<xs:element name="PRD_TypeName" type="xs:string" minOccurs="0"/>
<xs:element name="PRD_Type" type="xs:string" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:choice>
</xs:complexType>
</xs:element>
</xs:schema>
<diffgr:diffgram xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" xmlns:diffgr="urn:schemas-microsoft-com:xml-diffgram-v1">
<ProductTypeListResult xmlns="">
<ProductTypeListResult diffgr:id="ProductTypeListResult1" msdata:rowOrder="0">
<PRD_TypeId>2</PRD_TypeId>
<PRD_TypeName>ProdType2</PRD_TypeName>
<PRD_Type>S</PRD_Type>
</ProductTypeListResult>
<ProductTypeListResult diffgr:id="ProductTypeListResult2" msdata:rowOrder="1">
<PRD_TypeId>3</PRD_TypeId>
<PRD_TypeName>ProdType3</PRD_TypeName>
<PRD_Type>C</PRD_Type>
</ProductTypeListResult>
<ProductTypeListResult diffgr:id="ProductTypeListResult3" msdata:rowOrder="2">
<PRD_TypeId>4</PRD_TypeId>
<PRD_TypeName>ProdType4</PRD_TypeName>
</ProductTypeListResult>
</ProductTypeListResult>
</diffgr:diffgram>
</ProductTypeListResult>
</ProductTypeListResponse>
>
which is a .net dataset ..
So my question is how do i get at the information using my productTypeListResponse ? Can anyone give me a pointer ?
The WS Client should generate the proper code to access the result. I do not fully understand the wsdl that the .net service generates, but you should have methods such as
productTypeListResponse.ProductTypeListResult
on your response object. Check the example on groovy WS client site.
IMHO I would suggest you to use a more mature library such as spring ws

Resources