Forum Discussion

Markus_F's avatar
Markus_F
Occasional Contributor
7 years ago

Extract certain strings from JSON data strucure

Hello community,

 

I have the following JSON formatted data:

{
   "interfaces" : {
      "interface" : [
         {
            "interface-name" : "eth0"
         },
         {
            "interface-name" : "eth1"
         },
         {
            "interface-name" : "cons0"
         },
         {
            "interface-name" : "cons1"
         }
      ]
   }
}

I only want to have the strings"cons0" and "cons1" extracted/tansfered into e. g. an arrary for further usage in a SOAPUI test case. Does anyone has an idea?

 

Thanks in advance

Markus

 

  • Hello Markus,

    Given that you have a list of values that can vary between 0 and infinity, you can set properties from it easily enough, but now you have to give the property a name for each of those values. For each value a unique name must be created unless you don't care about how many values are in a list. The following builds on prior examples in this thread:

     

    filteredInterfaceNameList = [];
    interfaceNameList.each { name ->
       if (name.contains('cons')) {
          filteredInterfaceNameList.add (name)
       };
    };


    filteredInterfaceNameList.eachWithIndex { interfaceName, idx ->
       propName = "somePropertyNameValue" + idx.toString();
       propValue = interfaceName;
       testRunner.testCase.testSteps["Properties"].setPropertyValue( propName, propValue);
    };

    .

    .

    .
    You have never stated how you would use this dynamically, so I can only imagine... The above code allows you to dynamically write properties from 0 to infinity (or however many Smartbear will allow). :)

  • richie's avatar
    richie
    Community Hero

    Hi Markus_F

     

    I may be misunderstanding from your description - but if that .json you supplied is a response and you just need to grab 2 node values from the .json response - you can use a property transfer with a properties step to allow you to use the values later on in your test.

     

     

     

    i.e. so your step hierarchy in the test would be something like the following:

    POST --> generates the .json response you mention
    Property Transfer (grabs the 2 attribute values you want to use later and populates the Properties step with these)
    Properties step (the values transferred to this step from the original POST via the Property Transfer step)

    The way to do what you want is as follows:

     

    Run your POST to generate the response.

    Highlight the first attribute you want to transfer

    Click on the 'Transfer To' dropdown to launch the menu

    Select 'Add Properties step' (this will generate the property transfer step AND the Properties step)

    Click ok to select the name of the target property

    'Transfer to Property' form launches, click on ok to accept the defaults

     

    For the second attribute you want to grab

     

    Highlight the second attribute you want to transfer in the .json response

    Click on the 'Transfer To' button to launch the menu

    Select the relevant step that is the Properties test step created when the first attribute transfer was created

    Select 'new' to create a new property to hold the json attribute value

    Click ok to select the name of the target property

    Transfer to Property form launches, click on ok to accept the defaults

     

    At this point click on the Property Transfer step, click on each of the transfer and make sure both the Source and Target attributes are correctly populated - I've just run through this and I noticed that the second transfer's Target 'Property' field in the property transfer step is blank (might be a ReadyAPI! defect - as I keep doing this and it's always blank by default) - so I just set it to correct Property name (that is defined in the Properties step).

     

    If you now run your test (ensuring the Property Transfer step is BEFORE the Properties step) - the values you want to save for subsequent usage will be saved within your Properties step.

     

    Hope this helps!

     

    rich

    • Markus_F's avatar
      Markus_F
      Occasional Contributor

      Hi rich,

       

      thank you you for your input.

      Forgot to say that the data is queried from a server with REST GET request.

      The number of "interface-name" instances and the values in the REST response are varying. So, the easy way to just do a transfer from a fixed position into a property is not working.

       

      I was thinking about parsing all "interface-name" instances in the REST response with a filter string to store only a certain subset of values for further use.

       

      Any ideas how to do that in SOAPUI pro?

       

      BR

      Markus

      • richie's avatar
        richie
        Community Hero
        Hey

        I think you've a couple of choices here and I don't think my knowledge will do it as i think it'll probably be easier and more robust to rely on groovy (which is outside my skillset).

        I've had similar issues before and how i handled this using the GUI was to add in additional parms to my GET query to retrieve a specific number or set of records. In my scenario i filtered my GET so that a specific number of recorda were returned nd passed these to a property step. I then used a datasource (GRID) type to build an array of records which sourced the values from the Properties step. My test needed 6 records (so i setup 6 instances of the repeated attribute values into properties) and i got this working but it failed if the GET request returned less than 6 records.....so my solution wasnt very robust, but it got the job done....but as i say, it wasnt pretty nor robust.

        Perhaps one of the other lads can help out with a groovyscript option thats more robust than my approach? Or maybe there's a way of using the embedded functionality that I'm not aware of?

        Cheers,

        richie
  • aaronpliu's avatar
    aaronpliu
    Frequent Contributor

    Hi Markus_F,

     

    Can you please show more details on what you want?

    If you just want to extract certain string from JSON data, it should be easy to process.

    //

    def slurper = new groovy.json.JsonSlurper().parseText(YourJsonData)

    slurper.interfaces.interface.each{

        // do something

    }

  • TNeuschwanger's avatar
    TNeuschwanger
    Champion Level 1

    Hello,

    aaronpliu gave you the main tactict.  here is full groovy code to do what your original question asked...

    .

    .

    .

     

    import groovy.json.*;

     

    def sampleJSONtxt = '''
    {
       "interfaces" : {
       "interface" : [
    {
       "interface-name" : "eth0"
    },
    {
       "interface-name" : "eth1"
    },
    {
       "interface-name" : "cons0"
    },
    {
       "interface-name" : "cons1"
    }
    ]
    }
    }
    ''';

     

    def interfaceNameList = [];
    def sourceJSONobj = new JsonSlurper().parseText(sampleJSONtxt);
    sourceJSONobj.interfaces.interface.each { interfaceName ->
       log.info 'interfaceNameValue=' + interfaceName.'interface-name'.toString();
       interfaceNameList.add(interfaceName.'interface-name'.toString());
    };

     

    interfaceNameList.each { name ->
       log.info 'name of interface=' + name;
    };

     

    def filteredInterfaceNameList = [];
    interfaceNameList.each { name ->
       if (name.contains('cons')) {
          filteredInterfaceNameList.add (name)
          log.info 'name of filtered interface=' + name;
       };
    };

     

    log.info 'Test Step "' + testRunner.runContext.currentStep.name + '" done...';

    • Markus_F's avatar
      Markus_F
      Occasional Contributor

      Thank you for the code, it works fine :smileyhappy:

      One more question:

      Instead of having "cons0" and "cons1" in the log output window, how are they going into a property for further use?

       

      Markus

       

      • TNeuschwanger's avatar
        TNeuschwanger
        Champion Level 1

        Hello Markus,

        I think your request was for an array that contained filtered values... The code above and replicated here was the key to that. The "filteredInterfaceNameList" is your resultant array (list type) that only contains the filtered values from the whole list.
        The line above the log.info line is adding the filtered values to the empty list which you wanted to be able to do stuff with.


        def filteredInterfaceNameList = [];
        interfaceNameList.each { name ->
           if (name.contains('cons')) {
              filteredInterfaceNameList.add (name)
              log.info 'name of filtered interface=' + name;
           };
        };

        testRunner.testCase.testSteps["Properties"].setPropertyValue( "valueFromFilterA", filteredInterfaceNameList[0]);
        testRunner.testCase.testSteps["Properties"].setPropertyValue( "valueFromFilterB", filteredInterfaceNameList[1]);

        .

        .

        .
        Adding a couple more lines to that shows how to populate a test step named "Properies" which you can insert from a "Add Step" or "Insert Step" on the Test case.   With "Properties" content, you can use in other test steps in the test case.