Conditionally extract json response using Extension tool

tsworldtsworld Posts: 14
edited March 30 in SOAtest

I want to extract content for all titles having Red color from given Json response so I can send it in next Request.

eg. response:-

{
"titles":[
{
"name": "T1",
"color": "Red"
},
{
"name": "T2",
"color": "Green"
},
{
"name": "T2",
"color": "Red"
}
],
"content":[
"T1": "Some description 1",
"T2": "Some description 2",
"T3": "Some description 3",
]
}

Please help with code in Groovy for the Response extension tool. I am getting the whole response in input but not sure how to read this json and apply filter.

import com.parasoft.api.*;

public void test(Object input, ScriptingContext context)
{
Application.showMessage("input is: " + input);

}

Comments

  • benken_parasoftbenken_parasoft Posts: 891 ✭✭✭
    edited March 30

    Instead of writing a script, you can use a JSON Data Bank to extract values using an XPath expression that looks something like this:

    for $titleName in (/root/titles/item[color='Red']/name/text())
    return /root/content/item/*[local-name()=$titleName]/text()
    

    You can configure the JSON Data Bank to write the values to a Data Bank column which you could later get from a script or Extension tool using context.getValue("Generated Data Source", "nameOfDataBankColumn"). Or configure the JSON Data Bank to write the values to a Writable Data Source if you want some test to iterate over the list of values.

    Otherwise, if you prefer to write a Groovy script, the Jackson library works good for parsing JSON. Something like this:

    import com.parasoft.api.*
    import com.fasterxml.jackson.databind.*
    
    void test(Object input, ScriptingContext context) {
        ObjectMapper mapper = new ObjectMapper()
        JsonNode rootNode = mapper.readTree(input.toString())
        rootNode.get('titles').each { title ->
            if ('Red'.equals(title.get('color').textValue())) {
                String titleName = title.get('name').textValue()
                rootNode.get('content').each { content ->
                    JsonNode description = content.get(titleName)
                    if (description != null) {
                        Application.showMessage("found: " + description.textValue())
                    }
                }
            }
        }
    }
    
  • tsworldtsworld Posts: 14

    thanks @benken_parasoft the xpath was really helpful

  • tsworldtsworld Posts: 14

    Hi @benken_parasoft
    In continuation to my previous requirements, I want to get the substring from content but when I apply substring to the xpath (from index of / to end of string), it gives me only the first element instead of applying substring on each element and returning a list of substrings:-

    eg.
    for $titleName in (/root/titles/item[color='Red']/name/text()) return substring(/root/content/item/*[local-name()=$titleName]/text(), 5)

    Can also please provide any good documentation for complicated xpath on json?

  • benken_parasoftbenken_parasoft Posts: 891 ✭✭✭
    edited April 9

    it gives me only the first element instead of applying substring on each element and returning a list of substrings

    Your XPath returns the list of substrings just fine for me. Please make sure you are using the current SOAtest release. SOAtest 9.10.7 and earlier didn't properly handle XPaths that returned lists of non-nodes, like lists of strings, and incorrectly returned the first item in the list instead of the full list.

    Can also please provide any good documentation for complicated xpath on json?

    SOAtest's JSON-XML format: JSON Selector Reference

    General XPath function resources:
    w3schools: XSLT, XPath, and XQuery Functions
    w3c: XPath and XQuery Functions and Operators
    stackoverflow: https://stackoverflow.com/questions/tagged/xpath

  • tsworldtsworld Posts: 14

    thanks @benken_parasoft
    I am using SOAtest v9.9 so understanding from your answer that it is a defect in that version and will not be able to get the list of substrings

  • benken_parasoftbenken_parasoft Posts: 891 ✭✭✭

    In older releases, I've seen users work around the limitation by converting strings to text nodes, since lists of text nodes are returned as expected. I've seen something like this done:

    parse-xml(concat("<elem>", put_something_here, "</elem>"))/elem/text()
    

    In your case, you would wrap your substring function inside of this parse-xml function (replacing "put_something_here" with your substring function).
    You can also search the forum for "parse-xml" to find some examples.

Sign In or Register to comment.