In JMeter, does one JSON Extractor with three expressions parse the response body only once?
answer
- Compact configuration is not compact work
- Something is cached, but not the document
- Count the expressions, not the elements
- Three properties, all defaulting to the same size
basics
~10 sNo. JMeter's JSON Extractor loops over its semicolon-separated expressions and hands the response string to the JSON reader once per expression, so three expressions mean three parses of the same body.
solid answer
~60 sFolding several captures into one **JSON Extractor** saves an element, not a parse. The element iterates its semicolon-separated expression list and calls the JSON reader with the response **string** each time, so an N-expression element parses the same body N times. What the family caches for reuse across samples is the **compiled expression**, never the parsed document: the JSON Extractor keeps a per-thread map of expression to compiled query, the **JSON JMESPath Extractor** uses a cache sized by `jmespath.parser.cache.size` (default 400), the **XPath2 Extractor** by `xpath2query.parser.cache.size` (default 400), and the **CSS Selector Extractor** by `cssselector.parser.cache.size` (default 400, and only for its Jodd implementation). None of those holds a document; the one parsed body JMeter reuses belongs to the CSS Selector Extractor, which stashes it in the sampler context for the length of a single sample. The JSON JMESPath Extractor takes a single expression, so three of them parse three times too. Whether that parsing has become the constraint on a run is a load-testing question owned elsewhere; what JMeter tells you is how many parses your plan asks for.
code
properties · 12 lines# Apache JMeter 6.0.0 - compiled-expression caches.
# None of these caches a parsed response body.
# XPath2 Extractor, shipped commented in jmeter.properties
#xpath2query.parser.cache.size=400
# CSS Selector Extractor - Jodd implementation only, inert on JSoup
#cssselector.parser.cache.size=400
# JSON JMESPath Extractor - not shipped in jmeter.properties at all;
# read with a built-in default of 400
#jmespath.parser.cache.size=400go deeper
Recall that extraction is real work done per response, and that packing several expressions into one element is a tidiness choice rather than a saving.
Explain the loop the element runs over its expression list, and that every cache in this family holds compiled expressions rather than parsed documents — the CSS Selector Extractor's per-sample body stash aside.
Show the arithmetic on a real plan: expressions per element, elements per sampler, and which Apply to settings multiply the count.
Set the standard for what a plan is allowed to extract, and keep the distinct question of whether extraction constrains a run where it belongs rather than guessing at it.
Assumed version: Apache JMeter 6.0.0. ## What the element does per sample When a sampler in its scope finishes, the JSON Extractor does roughly this: 1. Collect the response bodies its **Apply to** setting selects, as strings. 2. Split its four semicolon-separated fields into aligned lists. 3. **For each expression in the list**, hand the response string plus that expression to the JSON reader and collect the results. 4. Write the variables for that expression, then move to the next one. Step 3 is the point. The reader is given a *string*, not a document object it built earlier, so it starts from the first character every time. Three expressions against one confirmation body is three full parses of that body, in that thread, for that sample. ## What JMeter actually caches Every structure-aware extractor in the family caches something, and with one exception it is always the compiled expression: | Element | Cache | Sizing property | Default | |---|---|---|---| | JSON Extractor | per-thread map of expression to compiled query | none — the map is unbounded but tiny in practice | — | | JSON JMESPath Extractor | shared compiled-expression cache | `jmespath.parser.cache.size` | 400 | | XPath2 Extractor | compiled-query cache keyed on query and namespaces | `xpath2query.parser.cache.size` | 400 | | CSS Selector Extractor | compiled-selector cache, **Jodd implementation only** | `cssselector.parser.cache.size` | 400 | Two details are easy to get wrong. First, `jmespath.parser.cache.size` is not shipped as a commented line in `jmeter.properties` the way the other two are — it is read with a built-in default of 400 and you have to know the key exists. Second, the CSS one applies only when you have switched the **CSS Selector Extractor Implementation** dropdown to Jodd; leave it blank or on JSoup and the property is inert. None of these caches a parsed document. The exception is the CSS Selector Extractor, which — separately from the selector cache above — stashes the parsed body in the sampler context, so several CSS extractors under one sampler share a parse until post-processing of that sample ends. The JSON Extractor's map is also **per thread**, created lazily and discarded when the thread finishes, so the compilation is repeated once per thread rather than once per test. ## The single-expression elements are not a workaround The JSON JMESPath Extractor accepts exactly one expression — no semicolon lists, no `_ALL` checkbox — and reads the body into a document once per element. So pulling three fields out of one confirmation body costs three parses there too, just spread across three elements rather than looped inside one. The XPath2 Extractor is the same shape: one query, and it builds a fresh document per call. No JSON or XPath element in JMeter parses a body once and serves several expressions from the result. The one place JMeter does reuse a parse is the CSS Selector Extractor, which stashes the parsed body in the sampler context so several CSS extractors under the same sampler share it — but each of those still takes exactly one expression, so it is no help for a JSON body. If you genuinely need many fields from one large body and the parse is the thing you want to spend less of, the honest options are to reduce the number of expressions, or to parse once yourself in a scripting element — which is a different leaf's subject, and a real trade-off rather than a free win. ## What this changes about plan design - **One multi-value JSON Extractor versus several single-expression JSON readers is a readability decision, not a performance one.** Both cost one parse per expression. Choose on whether you want to disable captures individually and name elements meaningfully. - **Capture what you use.** An expression left in from debugging is a whole extra parse of every response, in every thread, for the life of the run. - **Scope narrows the work.** *Apply to: Main sample only* keeps the extractor off sub-samples; the default reads the main sample, and widening it to sub-samples multiplies the parses by the number of sub-samples. - **The extractor's Match No. does not affect parsing cost.** Extract-all and extract-first read the same document; the difference is only which variables get written. ## Where this stops being a JMeter question Knowing your plan asks for three parses per response is a fact about the plan. Deciding whether that parsing has turned your load generator into the constraint — and how you would prove it rather than assume it — is load-testing method, and it belongs with performance-workload fundamentals and bottleneck attribution, not with the element reference. JMeter's contribution is arithmetic: expressions per element, elements per sampler, samplers per iteration. What that arithmetic means for a run is somebody else's chapter.
- Does splitting one three-expression JSON Extractor into three elements cost more?Marginally, and not in parsing. Each element re-walks the list of samples its Apply to setting selects and writes its own variables, but the number of body parses is three either way. The real difference is readability and the ability to disable one capture without touching the others.
- You set cssselector.parser.cache.size and nothing changes. Why might that be?That property is honoured only by the Jodd implementation of the CSS Selector Extractor. If the element's implementation dropdown is blank or set to JSoup — blank means JSoup — the property is never read. Check the dropdown before concluding the property does not work.
- How many times is an expression compiled over a run?Once per thread for the JSON Extractor, whose expression-to-query map is per-thread and discarded when the thread finishes. The JMESPath, XPath2 and Jodd CSS caches are shared and bounded by their size properties, so an expression is compiled once and reused across threads until it is evicted.
The expression cache is a saved search phrase, not a saved search result. JMeter remembers exactly what you wanted to look for, then opens the document at page one and reads it through again for every phrase you hand it.
saying these in an interview costs you the question
- Claims one element with many expressions parses the body once
- Thinks the cache size properties cache parsed documents
- Sets the CSS cache property while running the default implementation
- Leaves debugging expressions in a plan because they look free
- Assumes a single-expression JSON or XPath element avoids the repeated parsing