And a final observation using the GatewayScript debugger on your code. The reason the current code is rejecting the request is because the data has three less XXX that the if statement is looking for, so it will not match and will fail. I fixed that and it passes, although a much simpler XPath could handle this in one transform.xpath.
Regards,
Steve
Original Message:
Sent: Mon May 22, 2023 03:15 PM
From: Steve Linn
Subject: Gatewayscript variable in XPath
Hi Ashok and Joseph,
A lot of conversation while I was on vacation :-) Just a few comments:
//ACC_LIST_ARRAY[text()='333333333']
Just a FYI, the // XPath operator will inspect every element in document to see if there is a child element named ACC_LISTG_ARRAY with the desired value, so for performance, it is a best practice to specify the entire XPath instead of using the // short hand.
/AccountListPermissionResponse/AccountListPermission/AccountListPermission_REC/ACC_LIST_ARRAY[text()='333333333']
With this particular XML it probably isn't a big deal, but with larger and more complex XML it could make a difference.
Now seeing your full XML, I see that your soap root body element has a default namespace which is then inherited by all of its children elements. However, I ran your attached .js and it works, still, you're doing two xpaths to separately get the three ACC_LIST_ARRAY elements and the sibling elements ACC_PRMSN_ARRAY. Since you're looking to see if have the former with an XXXX value and the latter sibling element with a value of I, why not simply combine these into one xpath. If you get a result, you approve, if not, you reject?
expression: `/soapenv:Envelope/soapenv:Body/xmlns:CustomGetAccountListPermissionResponse/xmlns:CustomGetAccountListPermission/xmlns:CustomGetAccountListPermission_REC/[xmlns:ACC_LIST_ARRAY/text()= 'XXXXXXXXXXXXXXX' and xmlns:ACC_PRMSN_ARRAY/text() = 'I']`,
Note I made the expression value a string template so I didn't have to escape the single quotes in the XPath, but this will return all CustomGetAccountListPermission_REC elements whose child elements are the desired value. If you get an empty nodelist, you fail the test and indicate you have a permission error. The XPath is doing the iteration for you and really simplifies your code.
Regards,
Steve
------------------------------
Steve Linn
Senior Consulting I/T Specialist
IBM
Original Message:
Sent: Fri May 19, 2023 01:02 PM
From: Joseph Morgan
Subject: Gatewayscript variable in XPath
Consider changing this section:
var rootOptions = { expression: '/soapenv:Envelope/soapenv:Body/xmlns:CustomGetAccountListPermissionResponse/xmlns:CustomGetAccountListPermission/xmlns:CustomGetAccountListPermission_REC/xmlns:ACC_LIST_ARRAY/text()', xmldom: domTree, // your XML here namespace: { 'soapenv': 'http://schemas.xmlsoap.org/soap/envelope/', 'xmlns' :'http://www.infosys.com/response/CustomGetAccountListPermission', 'xsi' : 'http://www.w3.org/2001/XMLSchema-instance', 'hd' : 'http://www.infosys.com/response/header', 'ft' : 'http://www.infosys.com/response/footer' }};
with:
var rootOptions = { expression: '//ACC_LIST_ARRAY[text()=\\'XXXXXXXXXXXXXXX\\']', xmldom: domTree, // your XML here namespace: { 'soapenv': 'http://schemas.xmlsoap.org/soap/envelope/', 'xmlns' :'http://www.infosys.com/response/CustomGetAccountListPermission', 'xsi' : 'http://www.w3.org/2001/XMLSchema-instance', 'hd' : 'http://www.infosys.com/response/header', 'ft' : 'http://www.infosys.com/response/footer' }};
And then change the code from looping to just a simple verification of existence. That is, the XPATH response will return a nodeset with something in it or nothing in it.
------------------------------
Joseph Morgan
Original Message:
Sent: Wed May 17, 2023 09:44 AM
From: Ashok Beshra
Subject: Gatewayscript variable in XPath
Hi Joseph....
Thanks for your reply. I followed the above approach and able to do a proper xpath extracting in API Connect Gatewayscript(Code attached). In the runtime, our backend will return multiple accounts and we wanted to check whether the account number sent by API consumer is present in the list of accounts returned by Backend. We have put a for loop to iterate over the array and find a match. This is taking some time and we wanted to write optimized code to handle it better. Please suggest if there are any other alternative approaches to do this quickly. Thanks
Loop portion of the code. I have attached the full code as well for your reference.
transform.xpath(xpathOption, function(error, acctPrmsnNodeList) {
if (error) {
console.error('error while executing xpath - ' + error);
throw error;
} else {
acctPrmsn = acctPrmsnNodeList; // authorNodeList is DOM NodeList structure
console.error('Account Premission List length ' + acctPrmsn.length);
var flag = 'False';
for (var c=0; c<acctList.length; c++) {
//result += acctList.item(c).textContent + ', by ' + acctPrmsn.item(c).textContent + '\n';
if (acctList.item(c).textContent == 'XXXXXXXXXXXXXXX' && acctPrmsn.item(c).textContent == 'I') {
flag = 'True';
console.error('Allowed Account ' + acctList.item(c).textContent + 'Permission ' + acctPrmsn.item(c).textContent);
}
}
if(flag == 'False'){
console.error('Account Permission Error');
context.reject("GWSError","Account doesnt have Permission");
context.message.statusCode = "500";
}
}
------------------------------
Ashok Beshra
Original Message:
Sent: Tue May 16, 2023 07:30 AM
From: Joseph Morgan
Subject: Gatewayscript variable in XPath
I'm not sure the exact details of what is happening in your runtime or your Gateway script, but, what I gave you above is a sample XPATH for evaluating if a particular value exists within the XML you described. At least, that's what I think you are asking for.
With Gateway Script, if your XML is in a string, you'll need to use the XML.parse() function to get it into a proper document, and then use the Transform module "xpath()" function to evaluate the XPATH (or the proper variant of it).
So, using both my and Steve's examples above, I suspect you'll create an XPATH variable 'a' like in Steve's suggestion, then use the transform function as in my example to evaluate it (after converting any XML into a proper document using XML.parse(), of course).
------------------------------
Joseph Morgan
Original Message:
Sent: Tue May 16, 2023 05:02 AM
From: Ashok Beshra
Subject: Gatewayscript variable in XPath
Hi Joseph...
I tried the above and it is not working in API Connect Gateway script. This simply prints the above text and not retrieving the value.
------------------------------
Ashok Beshra
Original Message:
Sent: Mon May 15, 2023 10:11 AM
From: Joseph Morgan
Subject: Gatewayscript variable in XPath
Isn't this as easy as "//ACC_LIST_ARRAY[text()='333333333']"
------------------------------
Joseph Morgan
Original Message:
Sent: Mon May 15, 2023 09:41 AM
From: Ashok Beshra
Subject: Gatewayscript variable in XPath
Hi Steve...
I also have a similar requirement in the API Connect Gatewayscript where I have an account number lets say, '333333333' and the below XML response to check whether '333333333' is present. Please advise how xpath can be used to compare the XML array value against the static value (without looping through individual complex types in XML) and return a boolean true or false.
<AccountListPermissionResponse>
<AccountListPermission>
<AccountListPermission_REC>
<ACC_LIST_ARRAY>1234567890</ACC_LIST_ARRAY>
</AccountListPermission_REC>
<AccountListPermission_REC>
<ACC_LIST_ARRAY>9999999999</ACC_LIST_ARRAY>
</AccountListPermission_REC>
<AccountListPermission_REC>
<ACC_LIST_ARRAY>333333333</ACC_LIST_ARRAY>
</AccountListPermission_REC>
<AccountListPermission_REC>
<ACC_LIST_ARRAY>444444444</ACC_LIST_ARRAY>
</AccountListPermission_REC>
<AccountListPermission_REC>
<ACC_LIST_ARRAY>136890345</ACC_LIST_ARRAY>
</AccountListPermission_REC>
<AccountListPermission_REC>
<ACC_LIST_ARRAY>657535890</ACC_LIST_ARRAY>
</AccountListPermission_REC>
</AccountListPermission>
</AccountListPermissionResponse>
------------------------------
Ashok Beshra
Original Message:
Sent: Thu December 08, 2022 04:54 PM
From: Steve Linn
Subject: Gatewayscript variable in XPath
Hi Anusha,
In your attached source
var XMLFileName = "local:///xmlrequest.xml";var originalcontent= 'xml';var a="/source/route[@type=originalcontent]/Validation/text()";
your XPath is variable a is a string that has @type=originalcontent. I believe you want to have the variable value of originalcontent, ie, xml. You can do this in JavaScript with either concatenation or the use of template literals. For example
var a="/source/route[@type='" + originalcontent +"']/Validation/text()"; // string concatenation
var a=`/source/route[@type='${originalcontent}']/Validation/text()`; // template literal
both will accomplish the same thing, setting your variable a to the desired XPath /source/route[@type='xml']/Validation/text()
Note as well that in the predicate, the value being checked is a single quoted string .
Best Regards,
Steve
------------------------------
Steve Linn
Senior Consulting I/T Specialist
IBM
Original Message:
Sent: Thu December 08, 2022 05:19 AM
From: Anusha Pudari
Subject: Gatewayscript variable in XPath
Hi All,
We are trying to read a value from xml file using XPath through Gatewayscript, when the attribute type value checking with Gatewayscript variable value.
XML file:<source>
<route type="xml">
<Validation> Required </Validation>
</route>
<route type="json">
<Validation> Not Required </Validation>
</route>
</source>
In XSLT we used this XPath: /source/route[@type=$gatewayscriptvariable]/Validation/text()
If we hardcoded the value of type attribute it works as expected: /source/route[@type='xml']/Validation/text()
Please check attached Gatewayscript code and share your valuable thoughts here.
------------------------------
Anusha Pudari
------------------------------