Hello Apigeeks,
1. How do I update value in XML that comes from request payload?
2. How do I insert new element to the XML that comes from request payload?
For both items mentioned above, I tried with Javascript object model
var name = context.targetRequest.body.asXML.name; request.content.asXML context.proxyRequest.content.asXML
Unfortunately, these does not help me to do what I want. Basically,
1. I want to modify a value in XML, say <amount>0</amount>
update to <amount>200</amount>
2. I want to add new element to the XML, say <student><name>Thomson</name></student>
to <student><id>xx123</id><name>Thomson</name></student>
Not sure if it's matter, but it is a SOAP XML.
Solved! Go to Solution.
Patricia,
It does not work for update (that does not involves adding new namespace)
What do you mean? It works for me, with the example payload you provided.
The JS error happens because your JavaScript tool does not recognize the e4x extensions. There's no error in the JS that I gave you.
Attached please find a working example.
couple options come to mind.
1) use a 3rd-party Javascript XML Library. Import it as a resource and use it in your proxy (JS policy).
2) use a java callout and use inbuilt XML capabilities or your preferred 3rd-party XML library.
Do you have a sample of it?
When you use the .asXML thing, you get an XML object. The behavior of that XML object is defined as a part of larger set of xml capabilities, under the umbrella of E4X, which stands for EcmaScript for XML. E4X was a standard extension to EcmaScript (aka JavaScript) for a while, but then later was deprecated. It is still supported in the Rhino JS engine that Apigee uses, still supported in Apigee.
There is a way to do what you want using E4X, within a JS callout in Apigee. Unfortunately because E4X was deprecated from mainline Javascript, the documentation for the capability can be difficult to find. Sometimes it can be difficult to figure out how you should do a particular thing. But I can show you.
This worked for me.
Starting with this SOAP message:
<soap:Envelope xmlns:ns1="urn://24F9C86E-D207-4049-850B-02C48F138AA1" xmlns:soap="http://www.w3.org/2003/05/soap-envelope"> <soap:Header> <ns1:Anything/> </soap:Header> <soap:Body> <ns1:someMethod> <ns1:Status> <ns1:amount>0</ns1:amount> <ns1:student> <ns1:name>Thomson</ns1:name> </ns1:student> </ns1:Status> </ns1:someMethod> </soap:Body> </soap:Envelope>
I can use this JS code:
var message = context.getVariable('name_of_source_message'); if (message && message.content) { var xml = new XML(message.content); var ns1 = new Namespace('ns1','urn://24F9C86E-D207-4049-850B-02C48F138AA1'); var soap = new Namespace('soap','http://www.w3.org/2003/05/soap-envelope'); var body = xml.soap::Body; // modify the text value of a specific node var amountTextNode = body.ns1::someMethod.ns1::Status.ns1::amount.text(); amountTextNode.parent().setChildren('200'); // insert a new element var studentNode = body.ns1::someMethod.ns1::Status.ns1::student; var fragment = new XML('<id>xx123</id>'); fragment.setNamespace(ns1); studentNode.appendChild(fragment); // replace the content of the message with the modified version message.content = xml.toXMLString(); }
to get this result:
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:ns1="urn://24F9C86E-D207-4049-850B-02C48F138AA1"> <soap:Header> <ns1:Anything/> </soap:Header> <soap:Body> <ns1:someMethod> <ns1:Status> <ns1:amount>200</ns1:amount> <ns1:student> <ns1:name>Thomson</ns1:name> <ns1:id>xx123</ns1:id> </ns1:student> </ns1:Status> </ns1:someMethod> </soap:Body> </soap:Envelope>
You said:
Not sure if it's matter, but it is a SOAP XML.
Yes, it does matter. If you have a SOAP source message, you will need to deal with namespaces. I hope the code above shows you how to do that.
Hello @Dino-at-Google
Thanks for your help. Unfortunately, the payload does not get updated.
This is the request payload that I will be receiving.
<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:24F9C86E-D207-4049-850B-02C48F138AA1" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"> <soapenv:Header/> <soapenv:Body> <urn:SomeMethod soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"> <Amount xsi:type="xsd:string">0</Amount> <Student xsi:type="urn:3PBP0EU83" xmlns:urn="urn:UT21X4EM9"> <Name xsi:type="xsd:string">Thomson</Name> </Student> </urn:SomeMethod> </soapenv:Body> </soapenv:Envelope>
This is the new element that I want to insert.
<ID xsi:type="xsd:string"></ID>
My Javascript as I followed your step.
// get student id var studentid = "xx123"; // read soap xml from request payload var message = context.getVariable("request.content"); // modify request payload before sending to backend server if (message && message.content) { var xml = new XML(message.content); var soapenv = new Namespace("soapenv", "http://schemas.xmlsoap.org/soap/envelope/"); var urn = new Namespace("urn", "urn:24F9C86E-D207-4049-850B-02C48F138AA1"); var someMethod = xml.soapenv::Body.urn::SomeMethod; // modify the text value of a specific node var amountTextNode = someMethod.Amount.text(); amountTextNode.parent().setChildren("200"); // insert new element var studentNode = someMethod.Student; var fragXML = "<ID>" + studentid + "<ID>"; var fragment = new XML(fragXML); studentNode.appendChild(fragment); // replace the content of the message with the modified version message.content = xml.toXMLString(); }
There is no error, but the payload does not get updated.
yes, you need to modify the code that I showed you.
The code I wrote works with MY XML. It won't work with YOUR XML. Your XML has different elements, different namespaces. For example, your Student node has no XML namespace. (You noticed that). As another example, adding a namespace-qualified attribute, like
xsi:type="xsd:string"
, you need to use some specific syntax.
This worked for me.
var message = context.getVariable(properties.sourceMessage); var newStudentId = 'xx123'; if (message && message.content) { var xml = new XML(message.content); // get references to the namespaces uses in this document var ns1 = new Namespace('ns1','urn:24F9C86E-D207-4049-850B-02C48F138AA1'); var soap = new Namespace('soap','http://schemas.xmlsoap.org/soap/envelope/'); var someMethod = xml.soap::Body.ns1::SomeMethod; // modify the text value of a specific node var amountTextNode = someMethod.Amount.text(); amountTextNode.parent().setChildren('200'); // insert a new node under Student var studentNode = someMethod.Student; var fragment = new XML('<ID>' + newStudentId + '</ID>'); var xsi = new Namespace('xsi','http://www.w3.org/2001/XMLSchema-instance'); fragment.addNamespace(xsi); fragment.@xsi::type = 'xsd:string'; studentNode.appendChild(fragment); // replace the content of the message with the modified version message.content = xml.toXMLString(); }
The output I saw:
<soapenv:Body> <urn:SomeMethod soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"> <Amount xsi:type="xsd:string">200</Amount> <Student xmlns:urn="urn:UT21X4EM9" xsi:type="urn:3PBP0EU83"> <Name xsi:type="xsd:string">Thomson</Name> <ID xsi:type="xsd:string">xx123</ID> </Student> </urn:SomeMethod> </soapenv:Body>
Let me know if this helps.
Hello @Dino-at-Google
It does not work for update (that does not involves adding new namespace) and adding new element. I think it's because of the js error.
Patricia,
It does not work for update (that does not involves adding new namespace)
What do you mean? It works for me, with the example payload you provided.
The JS error happens because your JavaScript tool does not recognize the e4x extensions. There's no error in the JS that I gave you.
Attached please find a working example.
@dino-at-Google
Thanks for sharing. Your js works on my side as well.
The issue occurs when I modified to POST payload. I'm guessing it is on the verb and/or context.getvariable which I am using request.content.
Can you advise if I am missing any properties setup? I attached the proxy.
You have modified the JS to have this as the first statement:
var message = context.getVariable('request.payload');
The first statement should be this:
var message = context.getVariable('request');
When I made this change, your proxy worked for me.
curl $endpoint/test-soap-xml-e4x/updatepayload \ -X POST \ -H content-type:application/xml \ -d @sample-request-payload.xml
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:urn="urn:24F9C86E-D207-4049-850B-02C48F138AA1" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <soapenv:Header/> <soapenv:Body> <urn:SomeMethod soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"> <Amount xsi:type="xsd:string">200</Amount> <Student xmlns:urn="urn:UT21X4EM9" xsi:type="urn:3PBP0EU83"> <Name xsi:type="xsd:string">Thomson</Name> <ID xsi:type="xsd:string">xx123</ID> </Student> </urn:SomeMethod> </soapenv:Body> </soapenv:Envelope>
The sample-request-payload.xml looks like this:
<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:24F9C86E-D207-4049-850B-02C48F138AA1" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"> <soapenv:Header/> <soapenv:Body> <urn:SomeMethod soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"> <Amount xsi:type="xsd:string">0</Amount> <Student xsi:type="urn:3PBP0EU83" xmlns:urn="urn:UT21X4EM9"> <Name xsi:type="xsd:string">Thomson</Name> </Student> </urn:SomeMethod> </soapenv:Body> </soapenv:Envelope>
Attached please find the modified proxy.
this dosen't work for me neither
Hi,
I want to replace SubcriberID="1234" to SubscriberID="5678". Please advise.
Below is my sample request xml.
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:tns="http://xml.company.com/transaction">
<SOAP-ENV:Header>
<tns:Subscriber SubscriberID="1234" UserName="xxx"/>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
Please do not ask new questions in responses to old threads. It breaks search and usability for everyone.