Camel Apache: xpath to extract some value out of received XML - xpath

during my Camel routes, I query a server (a HTTP GET) and as a result, I receive a 200 OK with a XML body looking similar like this:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<userProfiles xmlns="http://www.mycompany.com/AEContext/xmldata">
<userProfile name="guest">
<userProfileAttributes>
<userProfileAttribute name="parameter1" value="data1" nameVisibility="ALL"/>
<userProfileAttribute name="parameter2" value="data2" nameVisibility="ALL"/>
<userProfileAttribute name="parameter3" value="data3" nameVisibility="ALL"/>
</userProfileAttributes>
</userProfile>
</userProfiles>
Any idea how I would be able to get the value of "parameter2" in the XML part (in my example 'data2') and store that value in an exchange property ? I guess by using an xpath expression ? Or ...
Thanks for your help.

An easy way to retrieve the value would be to use the XPath Language. It will allow you to extract the data you want and set it somewhere (header, body , ...). Here is how to set a parameter2 header with the value:
<setHeader headerName="parameter2">
<xpath resultType="java.lang.String">
/userProfiles/userProfile/userProfileAttributes/userProfileAttribute[2]/#value
</xpath>
</setHeader>
Using Java DSL
An example using the Java DSL and setting the message body:
final Namespaces ns = new Namespaces("c", "http://www.mycompany.com/AEContext/xmldata");
// existing code
from(...)
.setBody(
ns.xpath(
"/c:userProfiles/userProfile/userProfileAttributes/userProfileAttribute[2]/#value",
String.class)
)
.to(...);

Related

xpath assertion in soapui not working

I am reach up to this using xpath- //ns1:GetAtomicWeightResponse/ns1:GetAtomicWeightResult[1] but how to reach upto AtomicWeight.
<NewDataSet>
<Table>
<AtomicWeight>12.0115</AtomicWeight>
</Table>
</NewDataSet>
Here , I am not able to get value of AutomicWeight from table XML.
EDIT: Based on the comments from OP, adding the xml in the question.
<soap:Envelope
xmlns:soap="schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="w3.org/2001/XMLSchema-instance"
xmlns:xsd="w3.org/2001/XMLSchema">
<soap:Body>
<GetAtomicWeightResponse
xmlns="webserviceX.NET">
<GetAtomicWeightResult>
<![CDATA[<NewDataSet><Table><AtomicWeight>12.0115</AtomicWeight></Table></NewDataSet>]]>
</GetAtomicWeightResult>
</GetAtomicWeightResponse>
</soap:Body>
</soap:Envelope>
Consider Following response in your soap XML
<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>
<ConversionRateResponse xmlns="http://www.webserviceX.NET/">
<ConversionRateResult>1505.7</ConversionRateResult>
</ConversionRateResponse>
</soap:Body>
</soap:Envelope>
Xpath would be
declare namespace ns1='http://www.webserviceX.NET/';
//ns1:ConversionRateResponse[1]/ns1:ConversionRateResult[1]
Please use below xpath
//NewDataSet/Table/AtomicWeight
EDIT: Based on OP's data
Since, the data originally mentioned by you is in cdata that is why you were not able to get that value.
You can use below Groovy Script:
def xml = """<soap:Envelope xmlns:soap="schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="w3.org/2001/XMLSchema-instance" xmlns:xsd="w3.org/2001/XMLSchema">
<soap:Body>
<GetAtomicWeightResponse xmlns="webserviceX.NET">
<GetAtomicWeightResult><![CDATA[<NewDataSet><Table><AtomicWeight>12.0115</AtomicWeight></Table></NewDataSet>]]></GetAtomicWeightResult>
</GetAtomicWeightResponse>
</soap:Body>
</soap:Envelope>"""
def getData = { data, element -> new XmlSlurper().parseText(data).'**'.find{it.name() == element} }
def atomicWeight = getData((getData(xml, 'GetAtomicWeightResult') as String).trim(), 'AtomicWeight').text()
log.info atomicWeight
Or you can quickly try online Demo
If you are using it in SoapUI's test case, you do not have to add an additional Groovy Test step to get that value. Instead add the Script Assertion to the same request step (where you get that response) with below code(processing is same, but you do not have to use fixed xml, instead a dynamic response can be used).
Script Assertion
assert context.response, 'Response is empty or null'
def getData = { data, element -> new XmlSlurper().parseText(data).'**'.find{it.name() == element} }
def atomicWeight = getData((getData(context.response, 'GetAtomicWeightResult') as String).trim(), 'AtomicWeight').text()
log.info atomicWeight

Remove XML Namespaces from action Result

Using Web API and .NET Core and when I return an XML result I get the following:
<Test xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Response>
<Status>0</Status>
</Response>
</Test>
How do I remove the namespaces?
Here's part of my startup.cs file
services
.AddMvc(config =>
{
// Add XML Content Negotiation
config.RespectBrowserAcceptHeader = true;
config.InputFormatters.Add(new XmlSerializerInputFormatter());
config.OutputFormatters.Add(new XmlSerializerOutputFormatter(new XmlWriterSettings
{
OmitXmlDeclaration = true,
}));
})
.AddXmlDataContractSerializerFormatters()
.AddXmlSerializerFormatters()
.AddMvcOptions(opt => opt.FormatterMappings.SetMediaTypeMappingForFormat("xml", new MediaTypeHeaderValue("application/xml")));
Both XmlSerializer and DataContractSerializer formatters look for Content-Type or Accept header values for application/xml and text/xml. So if you register both the first formatters its possible that only one formatter in them would take effect.
If you want to support XmlSerializer, then register only that formatter and if you want to support both for some reason, make sure to change the content-types they look for. Example: application/xml-dcs, text/xml-dcs, application/xml-xmlser, text/xml-ser
In case of above issue, DataContractSerializerOutputFormatter is probably writing out the response and hence you are not seeing it take effect.

get json string from ajax response text

The response text of my Ajax request is this :
"<json>
<![CDATA[
{"status":true,"filterMap":{ "summary":"Summary","total":"Total","myProfileMsg":"Opening my profile, please wait","cgBase":"CG Base","export1":"Export"}}
]]>
<offsetinTime>19800000</offsetinTime></json>"
I want to extract just the json string from this.. ie. what i want is :
{"status":true,"filterMap":{ "summary":"Summary","total":"Total","myProfileMsg":"Opening my profile, please wait","cgBase":"CG Base","export1":"Export"}}
How do i do this?
Use replace() & split() functions of String to achieve it:
var json ='<json><![CDATA[{"status":true,"filterMap":{"summary":"Summary","total":"Total","myProfileMsg":"Opening my profile, please wait","cgBase":"CG Base","export1":"Export"}}]]><offsetinTime>19800000</offsetinTime></json>';
var extractedJson=json.replace('<json><![CDATA[','').split(']')[0];
document.body.innerHTML=extractedJson;

Access Purchase Orders via web service

We are busy developing an interface between Acumatica and our application via the web services. We are developing it in Ruby using the Savon gem.
We've got some of the exports working for the information we need, like this one for Vendor data:
We post the following SOAP call (after logging in):
<?xml version="1.0"?>
<env:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tns="http://www.acumatica.com/typed/" xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
<env:Body>
<tns:Export>
<tns:commands>
<tns:Command>
<tns:FieldName>AcctCD</tns:FieldName>
<tns:ObjectName>BAccount</tns:ObjectName>
<tns:Value>Account code</tns:Value>
</tns:Command>
<tns:Command>
<tns:FieldName>AcctName</tns:FieldName>
<tns:ObjectName>BAccount</tns:ObjectName>
<tns:Value>Account name</tns:Value>
</tns:Command>
</tns:commands>
<tns:filters/>
<tns:startRow>0</tns:startRow>
<tns:topCount>0</tns:topCount>
<tns:includeHeaders>false</tns:includeHeaders>
<tns:breakOnError>false</tns:breakOnError>
</tns:Export>
</env:Body>
</env:Envelope>
to the testing endpoint:
http://p3.tryacumatica.com/(W(10003))/Soap/AP303000.asmx?WSDL
We are also able to do the same kind of thing for Inventory and Sites. However we're struggling to get it working for Purchase Orders.
We post the following:
<?xml version="1.0"?>
<env:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tns="http://www.acumatica.com/typed/" xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
<env:Body>
<tns:Export>
<tns:commands>
<tns:Command>
<tns:FieldName>Type</tns:FieldName>
<tns:ObjectName>POOrder</tns:ObjectName>
<tns:Value>Type</tns:Value>
</tns:Command>
<tns:Command>
<tns:FieldName>OrderNbr</tns:FieldName>
<tns:ObjectName>POOrder</tns:ObjectName>
<tns:Value>Order number</tns:Value>
</tns:Command>
</tns:commands>
<tns:filters/>
<tns:startRow>0</tns:startRow>
<tns:topCount>0</tns:topCount>
<tns:includeHeaders>false</tns:includeHeaders>
<tns:breakOnError>false</tns:breakOnError>
</tns:Export>
</env:Body>
</env:Envelope>
to the testing endpoint:
http://p3.tryacumatica.com/(W(3))/Soap/PO301000.asmx?WSDL
We always just get an empty respone. Any ideas?
Check to see if PO module is turned on. Also check to see if the user has rights to query the PO objects. Does the database receive a query? One option is debug from the database side. See if the database picks up an queries submitted from the web service input.
I know these are simple ideas, but it's worth a look.
Well, my first question is why do you need a FULL list PO ? it could be a huge data.
PO has a composite key - Type, OrderNbr and basically using Export command you have to specify value like EveryOrderNbr
see link below
link
+
old c# example for SO
Content SO301000 = context.GetSchema();
context.Clear();
string[][] data = context.Export(new Command[]
{
SO301000.OrderSummary.ServiceCommands.EveryOrderType,
SO301000.OrderSummary.ServiceCommands.EveryOrderNbr,
SO301000.OrderSummary.OrderType,
SO301000.OrderSummary.OrderNbr,
SO301000.OrderSummary.Description,
SO301000.OrderSummary.Hold,
}, null,
new Filter[]
{
new Filter { Field = SO301000.OrderSummary.OrderType, Condition = FilterCondition.Equals, Value = "IN", Operator = FilterOperator.And },
new Filter { Field = SO301000.OrderSummary.OrderNbr, Condition = FilterCondition.Equals, Value = "23630843", Operator = FilterOperator.And }
},
0, false, true);

Unmarshalling JAX-RS response xml (content-type: text/xml) with formatting errors

The JAX-RS web service I'm calling is throwing xml content as text/html content type. On my side, I need to read the xml, and convert it to Java object.
The problem is: the response xml isn't formatted right and has newline characters in wrong places, such as - there are several newline characters before <?xml version="1.0" encoding="UTF-8"?> . This is causing problems trying to unmarshall it.
Is there a way I can unmarshall the response xml string though it has formatting problems?
Thanks in advance.
HttpGet httpGet = new HttpGet(uri);
HttpResponse response = client.execute(httpGet);
InputStream inputStream = response.getEntity().getContent();
JAXBContext context = JAXBContext.newInstance(MyClass.class);
MyClass myObj = (MyClass) context.createUnmarshaller().unmarshal(inputStream);
How about trimming the content before unmarshalling:
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.CharEncoding;
MyClass myObj = MyClass.class.cast(
context.createUnmarshaller().unmarshal(
IOUtils.toInputStream(
IOUtils.toString(
InputStream.class.cast(response.getEntity().getContent()),
CharEncoding.UTF_8
).trim(),
CharEncoding.UTF_8
)
)
);
Finally got the provider to send the response in xml/application format. However, as a way out, an option that I found is to save the content as a file, and then again retrieve content from the file.

Resources