This is an automated email from the ASF dual-hosted git repository.

fschumacher pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/jmeter.git


The following commit(s) were added to refs/heads/master by this push:
     new 0c97fd6  JSON Extractor and JSON JMESPath Extractor ignore sub-samples
0c97fd6 is described below

commit 0c97fd659f24960a89ff3344b7f71be9e70f1d28
Author: Felix Schumacher <[email protected]>
AuthorDate: Sun May 30 20:39:18 2021 +0200

    JSON Extractor and JSON JMESPath Extractor ignore sub-samples
    
    The UI for those elements suggest, that the extractors would
    look into sub-samples for matches (or even could be configured
    to use only values from the sub-samples). Adapt the implementation
    to make that assumption true.
    
    Bugzilla Id: 65269
---
 .../extractor/json/jmespath/JMESPathExtractor.java | 48 +++++++-----
 .../extractor/json/jsonpath/JSONPostProcessor.java | 27 ++++---
 .../jmeter/extractor/TestJSONPostProcessor.java    | 88 +++++++++++++++++++---
 .../json/jmespath/TestJMESPathExtractor.java       | 73 ++++++++++++++++++
 xdocs/changes.xml                                  |  1 +
 xdocs/usermanual/component_reference.xml           | 21 ++++--
 6 files changed, 213 insertions(+), 45 deletions(-)

diff --git 
a/src/components/src/main/java/org/apache/jmeter/extractor/json/jmespath/JMESPathExtractor.java
 
b/src/components/src/main/java/org/apache/jmeter/extractor/json/jmespath/JMESPathExtractor.java
index 78e72da..8cad7e6 100644
--- 
a/src/components/src/main/java/org/apache/jmeter/extractor/json/jmespath/JMESPathExtractor.java
+++ 
b/src/components/src/main/java/org/apache/jmeter/extractor/json/jmespath/JMESPathExtractor.java
@@ -20,7 +20,10 @@ package org.apache.jmeter.extractor.json.jmespath;
 import java.io.IOException;
 import java.io.Serializable;
 import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
 import java.util.List;
+import java.util.stream.Collectors;
 
 import org.apache.commons.lang3.StringUtils;
 import org.apache.jmeter.processor.PostProcessor;
@@ -38,6 +41,8 @@ import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fasterxml.jackson.databind.node.ArrayNode;
 
+import io.burt.jmespath.Expression;
+
 /**
  * JMESPATH based extractor
  *
@@ -60,7 +65,7 @@ public class JMESPathExtractor extends 
AbstractScopedTestElement
     public void process() {
         JMeterContext context = getThreadContext();
         JMeterVariables vars = context.getVariables();
-        String jsonResponse = getData(vars, context);
+        List<String> jsonResponse = getData(vars, context);
         String refName = getRefName();
         String defaultValue = getDefaultValue();
         int matchNumber;
@@ -71,21 +76,25 @@ public class JMESPathExtractor extends 
AbstractScopedTestElement
         }
         final String jsonPathExpression = getJmesPathExpression().trim();
         clearOldRefVars(vars, refName);
-        if (StringUtils.isEmpty(jsonResponse)) {
+        if (jsonResponse.isEmpty()) {
             handleEmptyResponse(vars, refName, defaultValue);
             return;
         }
 
         try {
-            JsonNode actualObj = OBJECT_MAPPER.readValue(jsonResponse, 
JsonNode.class);
-            JsonNode result = 
JMESPathCache.getInstance().get(jsonPathExpression).search(actualObj);
-            if (result.isNull()) {
-                handleNullResult(vars, refName, defaultValue, matchNumber);
-                return;
+            List<String> resultList = new ArrayList<>();
+            Expression<JsonNode> searchExpression = 
JMESPathCache.getInstance().get(jsonPathExpression);
+            for (String response: jsonResponse) {
+                JsonNode actualObj = OBJECT_MAPPER.readValue(response, 
JsonNode.class);
+                JsonNode result = searchExpression.search(actualObj);
+                if (result.isNull()) {
+                    continue;
+                }
+                resultList.addAll(splitJson(result));
             }
-            List<String> resultList = splitJson(result);
             // if more than one value extracted, suffix with "_index"
-            if (resultList.size() > 1) {
+            int size = resultList.size();
+            if (size > 1) {
                 handleListResult(vars, refName, defaultValue, matchNumber, 
resultList);
             } else if (resultList.isEmpty()){
                 handleNullResult(vars, refName, defaultValue, matchNumber);
@@ -94,7 +103,7 @@ public class JMESPathExtractor extends 
AbstractScopedTestElement
                 // else just one value extracted
                 handleSingleResult(vars, refName, matchNumber, resultList);
             }
-            vars.put(refName + REF_MATCH_NR, 
Integer.toString(resultList.size()));
+            vars.put(refName + REF_MATCH_NR, Integer.toString(size));
         } catch (Exception e) {
             // if something wrong, default value added
             if (log.isDebugEnabled()) {
@@ -155,23 +164,26 @@ public class JMESPathExtractor extends 
AbstractScopedTestElement
         vars.put(refName, defaultValue);
     }
 
-    private String getData(JMeterVariables vars, JMeterContext context) {
-        String jsonResponse = null;
+    private List<String> getData(JMeterVariables vars, JMeterContext context) {
         if (isScopeVariable()) {
-            jsonResponse = vars.get(getVariableName());
+            String jsonResponse = vars.get(getVariableName());
             if (log.isDebugEnabled()) {
                 log.debug("JMESExtractor is using variable: {}, which content 
is: {}", getVariableName(), jsonResponse);
             }
+            return Arrays.asList(jsonResponse);
         } else {
             SampleResult previousResult = context.getPreviousResult();
             if (previousResult != null) {
-                jsonResponse = previousResult.getResponseDataAsString();
-            }
-            if (log.isDebugEnabled()) {
-                log.debug("JMESExtractor {} working on Response: {}", 
getName(), jsonResponse);
+                List<String> results = getSampleList(previousResult).stream()
+                        .map(SampleResult::getResponseDataAsString)
+                        .collect(Collectors.toList());
+                if (log.isDebugEnabled()) {
+                    log.debug("JMESExtractor {} working on Responses: {}", 
getName(), results);
+                }
+                return results;
             }
         }
-        return jsonResponse;
+        return Collections.emptyList();
     }
 
     public List<String> splitJson(JsonNode jsonNode) throws IOException {
diff --git 
a/src/components/src/main/java/org/apache/jmeter/extractor/json/jsonpath/JSONPostProcessor.java
 
b/src/components/src/main/java/org/apache/jmeter/extractor/json/jsonpath/JSONPostProcessor.java
index 56bbe2e..6e61f73 100644
--- 
a/src/components/src/main/java/org/apache/jmeter/extractor/json/jsonpath/JSONPostProcessor.java
+++ 
b/src/components/src/main/java/org/apache/jmeter/extractor/json/jsonpath/JSONPostProcessor.java
@@ -18,10 +18,12 @@
 package org.apache.jmeter.extractor.json.jsonpath;
 
 import java.io.Serializable;
+import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.List;
+import java.util.stream.Collectors;
 
-import org.apache.commons.lang3.StringUtils;
 import org.apache.jmeter.processor.PostProcessor;
 import org.apache.jmeter.samplers.SampleResult;
 import org.apache.jmeter.testelement.AbstractScopedTestElement;
@@ -62,7 +64,7 @@ public class JSONPostProcessor
     public void process() {
         JMeterContext context = getThreadContext();
         JMeterVariables vars = context.getVariables();
-        String jsonResponse = extractJsonResponse(context, vars);
+        List<String> jsonResponses = extractJsonResponse(context, vars);
         String[] refNames = getRefNames().split(SEPARATOR);
         String[] jsonPathExpressions = 
getJsonPathExpressions().split(SEPARATOR);
         String[] defaultValues = getDefaultValues().split(SEPARATOR);
@@ -76,11 +78,13 @@ public class JSONPostProcessor
             String currentJsonPath = jsonPathExpressions[i].trim();
             clearOldRefVars(vars, currentRefName);
             try {
-                if (StringUtils.isEmpty(jsonResponse)) {
+                if (jsonResponses.isEmpty()) {
                     handleEmptyResponse(vars, defaultValues, i, 
currentRefName);
                 } else {
-                    List<Object> extractedValues = localMatcher.get()
-                            .extractWithJsonPath(jsonResponse, 
currentJsonPath);
+                    List<Object> extractedValues = new ArrayList<>();
+                    for (String jsonResponse: jsonResponses) {
+                        
extractedValues.addAll(localMatcher.get().extractWithJsonPath(jsonResponse, 
currentJsonPath));
+                    }
                     // if no values extracted, default value added
                     if (extractedValues.isEmpty()) {
                         handleEmptyResult(vars, defaultValues, i, matchNumber, 
currentRefName);
@@ -198,23 +202,26 @@ public class JSONPostProcessor
         vars.put(currentRefName, defaultValues[i]);
     }
 
-    private String extractJsonResponse(JMeterContext context, JMeterVariables 
vars) {
+    private List<String> extractJsonResponse(JMeterContext context, 
JMeterVariables vars) {
         String jsonResponse = "";
         if (isScopeVariable()) {
-            jsonResponse = vars.get(getVariableName());
             if (log.isDebugEnabled()) {
                 log.debug("JSON Extractor is using variable: {}, which content 
is: {}", getVariableName(), jsonResponse);
             }
+            return Arrays.asList(vars.get(getVariableName()));
         } else {
             SampleResult previousResult = context.getPreviousResult();
             if (previousResult != null) {
-                jsonResponse = previousResult.getResponseDataAsString();
+                List<String> results = getSampleList(previousResult).stream()
+                        .map(SampleResult::getResponseDataAsString)
+                        .collect(Collectors.toList());
                 if (log.isDebugEnabled()) {
-                    log.debug("JSON Extractor {} working on Response: {}", 
getName(), jsonResponse);
+                    log.debug("JSON Extractor {} working on Responses: {}", 
getName(), results);
                 }
+                return results;
             }
         }
-        return jsonResponse;
+        return Collections.emptyList();
     }
 
     private void clearOldRefVars(JMeterVariables vars, String refName) {
diff --git 
a/src/components/src/test/java/org/apache/jmeter/extractor/TestJSONPostProcessor.java
 
b/src/components/src/test/java/org/apache/jmeter/extractor/TestJSONPostProcessor.java
index 99ee282..acc6775 100644
--- 
a/src/components/src/test/java/org/apache/jmeter/extractor/TestJSONPostProcessor.java
+++ 
b/src/components/src/test/java/org/apache/jmeter/extractor/TestJSONPostProcessor.java
@@ -21,24 +21,80 @@ import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 
 import java.nio.charset.StandardCharsets;
+import java.util.function.Consumer;
+import java.util.stream.Stream;
 
 import org.apache.jmeter.extractor.json.jsonpath.JSONPostProcessor;
 import org.apache.jmeter.samplers.SampleResult;
+import org.apache.jmeter.testelement.AbstractScopedTestElement;
 import org.apache.jmeter.threads.JMeterContext;
 import org.apache.jmeter.threads.JMeterContextService;
 import org.apache.jmeter.threads.JMeterVariables;
 import org.hamcrest.CoreMatchers;
 import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
 
 import net.minidev.json.parser.JSONParser;
 import net.minidev.json.parser.ParseException;
 
-public class TestJSONPostProcessor {
+class TestJSONPostProcessor {
 
     private static final String VAR_NAME = "varName";
 
+    private enum AccessMode {
+        ALL(AbstractScopedTestElement::setScopeAll),
+        PARENT(AbstractScopedTestElement::setScopeParent),
+        CHILDREN(AbstractScopedTestElement::setScopeChildren);
+
+        private Consumer<AbstractScopedTestElement> applier;
+
+        AccessMode(Consumer<AbstractScopedTestElement> applier) {
+            this.applier = applier;
+        }
+
+        void configure(AbstractScopedTestElement element) {
+            applier.accept(element);
+        }
+    }
+
+    private static Stream<Arguments> provideArgumentsForScopes() {
+        return Stream.of(
+                Arguments.of(AccessMode.ALL, "$.a", "1", "23", "2"),
+                Arguments.of(AccessMode.ALL, "$.a", "2", "42", "2"),
+                Arguments.of(AccessMode.ALL, "$.b", "0", "parent_only", "1"),
+                Arguments.of(AccessMode.ALL, "$.c", "0", "child_only", "1"),
+                Arguments.of(AccessMode.PARENT, "$.a", "1", "23", "1"),
+                Arguments.of(AccessMode.PARENT, "$.b", "0", "parent_only", 
"1"),
+                Arguments.of(AccessMode.PARENT, "$.c", "0", "NONE", "0"),
+                Arguments.of(AccessMode.CHILDREN, "$.a", "1", "42", "1"),
+                Arguments.of(AccessMode.CHILDREN, "$.b", "0", "NONE", "0"),
+                Arguments.of(AccessMode.CHILDREN, "$.c", "0", "child_only", 
"1")
+            );
+    }
+
+    @ParameterizedTest()
+    @MethodSource("provideArgumentsForScopes")
+    void testAssertionWithScope(AccessMode accessMode, String path, String 
matchNumber, String resultObject,
+            String resultCount) {
+        JMeterContext context = JMeterContextService.getContext();
+        JSONPostProcessor processor = setupProcessor(context, matchNumber, 
false);
+        JMeterVariables vars = new JMeterVariables();
+        processor.setDefaultValues("NONE");
+        processor.setJsonPathExpressions(path);
+        processor.setRefNames("result");
+        accessMode.configure(processor);
+        SampleResult sampleResult = createSampleResult("{\"a\": 23, \"b\": 
\"parent_only\"}");
+        sampleResult.addSubResult(createSampleResult("{\"a\": 42, \"c\": 
\"child_only\"}"));
+        context.setPreviousResult(sampleResult);
+        context.setVariables(vars);
+        processor.process();
+        assertThat(vars.get("result"), CoreMatchers.is(resultObject));
+    }
+
     @Test
-    public void testProcessAllElementsOneMatch() {
+    void testProcessAllElementsOneMatch() {
         JMeterContext context = JMeterContextService.getContext();
         JSONPostProcessor processor = setupProcessor(context, "-1", true);
         JMeterVariables vars = new JMeterVariables();
@@ -55,7 +111,7 @@ public class TestJSONPostProcessor {
     }
 
     @Test
-    public void testProcessAllElementsMultipleMatches() {
+    void testProcessAllElementsMultipleMatches() {
         JMeterContext context = JMeterContextService.getContext();
         JSONPostProcessor processor = setupProcessor(context, "-1", true);
         JMeterVariables vars = new JMeterVariables();
@@ -72,7 +128,7 @@ public class TestJSONPostProcessor {
     }
 
     @Test
-    public void testProcessRandomElementMultipleMatches() {
+    void testProcessRandomElementMultipleMatches() {
         JMeterContext context = JMeterContextService.getContext();
         JSONPostProcessor processor = setupProcessor(context, "0", true);
         JMeterVariables vars = new JMeterVariables();
@@ -90,7 +146,7 @@ public class TestJSONPostProcessor {
     }
 
     @Test
-    public void testPR235CaseEmptyResponse() {
+    void testPR235CaseEmptyResponse() {
         JMeterContext context = JMeterContextService.getContext();
         JSONPostProcessor processor = setupProcessor(context, "-1", true);
         JMeterVariables vars = new JMeterVariables();
@@ -112,7 +168,7 @@ public class TestJSONPostProcessor {
     }
 
     @Test
-    public void testCaseEmptyVarBug62860() {
+    void testCaseEmptyVarBug62860() {
         JMeterContext context = JMeterContextService.getContext();
         JSONPostProcessor processor = setupProcessor(context, "0", false);
         JMeterVariables vars = new JMeterVariables();
@@ -133,7 +189,7 @@ public class TestJSONPostProcessor {
     }
 
     @Test
-    public void testPR235CaseMatchOneWithZero() {
+    void testPR235CaseMatchOneWithZero() {
         JMeterContext context = JMeterContextService.getContext();
         JSONPostProcessor processor = setupProcessor(context, "-1", true);
         JMeterVariables vars = new JMeterVariables();
@@ -157,7 +213,7 @@ public class TestJSONPostProcessor {
     }
 
     @Test
-    public void testBug59609() throws ParseException {
+    void testBug59609() throws ParseException {
         JMeterContext context = JMeterContextService.getContext();
         JSONPostProcessor processor = setupProcessor(context, "0", false);
 
@@ -181,7 +237,7 @@ public class TestJSONPostProcessor {
     }
 
     @Test
-    public void testExtractSimpleArrayElements() {
+    void testExtractSimpleArrayElements() {
         JMeterContext context = JMeterContextService.getContext();
         JSONPostProcessor processor = setupProcessor(context, "-1");
         String data = "[1,2,3]";
@@ -204,7 +260,7 @@ public class TestJSONPostProcessor {
     }
 
     @Test
-    public void testExtractComplexElements() {
+    void testExtractComplexElements() {
         JMeterContext context = JMeterContextService.getContext();
         JSONPostProcessor processor = setupProcessor(context, "-1");
         String data = "[{\"a\":[1,{\"d\":2},3]},[\"b\",{\"h\":23}],3]";
@@ -227,11 +283,18 @@ public class TestJSONPostProcessor {
         assertEquals("3", vars.get(VAR_NAME + "_matchNr"));
     }
 
-    private JSONPostProcessor setupProcessor(JMeterContext context, String 
matchNumbers) {
+
+    private static JSONPostProcessor setupProcessor(JMeterContext context, 
String matchNumbers) {
         return setupProcessor(context, matchNumbers, true);
     }
 
-    private JSONPostProcessor setupProcessor(JMeterContext context,
+    private static SampleResult createSampleResult(String data) {
+        SampleResult result = new SampleResult();
+        result.setResponseData(data, null);
+        return result;
+    }
+
+    private static JSONPostProcessor setupProcessor(JMeterContext context,
             String matchNumbers, boolean computeConcatenation) {
         JSONPostProcessor processor = new JSONPostProcessor();
         processor.setThreadContext(context);
@@ -241,4 +304,5 @@ public class TestJSONPostProcessor {
         return processor;
     }
 
+
 }
diff --git 
a/src/components/src/test/java/org/apache/jmeter/extractor/json/jmespath/TestJMESPathExtractor.java
 
b/src/components/src/test/java/org/apache/jmeter/extractor/json/jmespath/TestJMESPathExtractor.java
index 87f72d0..c9f2b3e 100644
--- 
a/src/components/src/test/java/org/apache/jmeter/extractor/json/jmespath/TestJMESPathExtractor.java
+++ 
b/src/components/src/test/java/org/apache/jmeter/extractor/json/jmespath/TestJMESPathExtractor.java
@@ -21,8 +21,10 @@ import static org.hamcrest.MatcherAssert.assertThat;
 
 import java.util.Arrays;
 import java.util.Collection;
+import java.util.function.Consumer;
 
 import org.apache.jmeter.samplers.SampleResult;
+import org.apache.jmeter.testelement.AbstractScopedTestElement;
 import org.apache.jmeter.threads.JMeterContext;
 import org.apache.jmeter.threads.JMeterContextService;
 import org.apache.jmeter.threads.JMeterVariables;
@@ -235,6 +237,77 @@ public class TestJMESPathExtractor {
     }
 
     @RunWith(Parameterized.class)
+    public static class ScopedSamples {
+
+        enum AccessMode {
+            ALL(AbstractScopedTestElement::setScopeAll),
+            PARENT(AbstractScopedTestElement::setScopeParent),
+            CHILDREN(AbstractScopedTestElement::setScopeChildren);
+
+            private Consumer<AbstractScopedTestElement> applier;
+
+            AccessMode(Consumer<AbstractScopedTestElement> applier) {
+                this.applier = applier;
+            }
+
+            void configure(AbstractScopedTestElement element) {
+                applier.accept(element);
+            }
+        }
+
+        private AccessMode accessMode;
+        private String resultObject;
+        private String resultCount;
+        private String matchNumber;
+        private String path;
+
+        public ScopedSamples(AccessMode accessMode, String path, String 
matchNumber, String result, String resultCount) {
+            this.accessMode = accessMode;
+            this.path = path;
+            this.matchNumber = matchNumber;
+            this.resultObject = result;
+            this.resultCount = resultCount;
+        }
+
+        @Parameters(name = "{index}: Mode: {0} Path: {1} MatchNr: {2} Result: 
{3} Count: {4}")
+        public static Collection<Object[]> data() {
+            return Arrays.asList(
+                    new Object[][] {
+                        { AccessMode.ALL, "a", "1", "23", "2" },
+                        { AccessMode.ALL, "a", "2", "42", "2" },
+                        { AccessMode.ALL, "b", "0", "parent_only", "1" },
+                        { AccessMode.ALL, "c", "0", "child_only", "1" },
+                        { AccessMode.PARENT, "a", "1", "23", "1" },
+                        { AccessMode.PARENT, "b", "0", "parent_only", "1" },
+                        { AccessMode.PARENT, "c", "0", "NONE", "0" },
+                        { AccessMode.CHILDREN, "a", "1", "42", "1" },
+                        { AccessMode.CHILDREN, "b", "0", "NONE", "0" },
+                        { AccessMode.CHILDREN, "c", "0", "child_only", "1" },
+                    }
+            );
+        }
+
+        @Test
+        public void testRandomElementAllMatches() {
+            SampleResult sampleResult = new SampleResult();
+            JMeterVariables vars = new JMeterVariables();
+            JMESPathExtractor processor = setupProcessor(vars, sampleResult, 
"{\"a\": 23, \"b\": \"parent_only\"}", false, matchNumber);
+            SampleResult subSample = new SampleResult();
+            subSample.setResponseData("{\"a\": 42, \"c\": \"child_only\"}", 
null);
+            sampleResult.addSubResult(subSample);
+
+            processor.setJmesPathExpression(path);
+            accessMode.configure(processor);
+
+            processor.process();
+            assertThat(vars.get(REFERENCE_NAME), 
CoreMatchers.is(resultObject));
+            assertThat(vars.get(REFERENCE_NAME + "_1"), 
CoreMatchers.is(CoreMatchers.nullValue()));
+            assertThat(vars.get(REFERENCE_NAME_MATCH_NUMBER), 
CoreMatchers.is(resultCount));
+        }
+
+    }
+
+    @RunWith(Parameterized.class)
     public static class SourceVarOrResponse {
         private boolean fromVariables;
 
diff --git a/xdocs/changes.xml b/xdocs/changes.xml
index 845f5e9..be5d038 100644
--- a/xdocs/changes.xml
+++ b/xdocs/changes.xml
@@ -168,6 +168,7 @@ Summary
 <ul>
   <li><bug>65257</bug>JMESPathExtractor writes error log entries if JMESPath 
filter returns empty result</li>
   <li><bug>65259</bug>JMESPathExtractor Attribute <code>Match No.</code> 
Required</li>
+  <li><bug>65269</bug>JSON Extractor and JSON JMESPath Extractor ignore 
sub-samples</li>
 </ul>
 
 <h3>Functions</h3>
diff --git a/xdocs/usermanual/component_reference.xml 
b/xdocs/usermanual/component_reference.xml
index be770b4..c3e08b7 100644
--- a/xdocs/usermanual/component_reference.xml
+++ b/xdocs/usermanual/component_reference.xml
@@ -6327,15 +6327,26 @@ It will allow you to extract in a very easy way text 
content, see <a href="https
 </description>
 <properties>
     <property name="Name" required="No">Descriptive name for this element that 
is shown in the tree.</property>
-    <property name="Names of created variables" required="Yes">Semi-colon 
separated names of variables that will contain the results of JSON-PATH 
expressions (must match number of JSON-PATH expressions)</property>
-    <property name="JSON Path Expressions" required="Yes">Semi-colon separated 
JSON-PATH expressions (must match number of variables)</property>
-    <property name="Default Values" required="No">Semi-colon separated default 
values if JSON-PATH expressions do not return any result(must match number of 
variables)</property>
-    <property name="Match No. (0 for Random)" required="No">If the JSON Path 
query leads to many results, you can choose which one(s) to extract as 
Variables:
+    <property name="Apply to:" required="Yes">
+        This is for use with samplers that can generate sub-samples,
+        e.g. HTTP Sampler with embedded resources, Mail Reader or samples 
generated by the Transaction Controller.
+        <dl>
+        <dt><code>Main sample only</code></dt><dd>only applies to the main 
sample</dd>
+        <dt><code>Sub-samples only</code></dt><dd>only applies to the 
sub-samples</dd>
+        <dt><code>Main sample and sub-samples</code></dt><dd>applies to 
both.</dd>
+        <dt><code>JMeter Variable Name to use</code></dt><dd>extraction is to 
be applied to the contents of the named variable</dd>
+        </dl>
+    </property>
+    <property name="Names of created variables" required="Yes">Semicolon 
separated names of variables that will contain the results of JSON-PATH 
expressions (must match number of JSON-PATH expressions)</property>
+    <property name="JSON Path Expressions" required="Yes">Semicolon separated 
JSON-PATH expressions (must match number of variables)</property>
+    <property name="Default Values" required="No">Semicolon separated default 
values if JSON-PATH expressions do not return any result(must match number of 
variables)</property>
+    <property name="Match Numbers" required="No">For each JSON Path 
Expression, if the JSON Path query leads to many results, you can choose which 
one(s) to extract as Variables:
     <ul>
         <li><code>0</code>: means random (Default Value)</li>
         <li><code>-1</code> means extract all results, they will be named as 
<code><em>&lt;variable name&gt;</em>_N</code> (where <code>N</code> goes from 1 
to Number of results)</li>
-        <li><code>X</code>: means extract the X<sup>th</sup> result. If this 
X<sup>th</sup> is greater than number of matches, then nothing is returned. 
Default value will be used</li>
+        <li><code>X</code>: means extract the <em>X</em><sup>th</sup> result. 
If this <em>X</em><sup>th</sup> is greater than number of matches, then nothing 
is returned. Default value will be used</li>
     </ul>
+    The numbers have to be given as a Semicolon separated list. The number of 
elements in that list have to match the number of given JSON Path Expressions. 
If left empty, the value <code>0</code> will be used as default for every 
expression.
     </property>
     <property name="Compute concatenation var" required="No">If many results 
are found, plugin will concatenate them using ‘<code>,</code>’ separator and 
store it in a var named <code><em>&lt;variable 
name&gt;</em>_ALL</code></property>
 </properties>

Reply via email to