---
title: Updating JMeter Performance Tests with an XML parser
url: https://blog.octoperf.com/updating-jmeter-performance-tests-with-an-xml-parser/
date: '2022-11-08'
authors:
- sjenkins
categories:
- JMeter
tags:
- JMeter
- XML
- IntelliJ
- Sampler
- JMX
- Proxy
description: Parsing a JMeter Test using a XML Parser to understand how we can quickly and efficiently make multiple JMeter Test changes through code.
---

# Updating JMeter Performance Tests with an XML parser

When building performance tests, we all understand the value of using [properties](https://jmeter.apache.org/usermanual/functions.html "properties") or [variables](https://jmeter.apache.org/usermanual/functions.html "variables") to store static values outside of our tests.
This ensures that any changes to these values need only be made in one place rather than having to make these changes in many tests.

Sometime though you may have inherited a suite of [JMeter](https://jmeter.apache.org/ "JMeter") tests, or you were **
under pressure to develop these tests** and in order to do so you hardcoded values in your tests. This means that if
anything changes, an endpoint or the server-name or even the payload of a sampler then you need to make changes to these
static values in your tests.


It is possible that you have many tests to update, or you have decided that you are going to update the static values
with properties or variables so that in the future any changes can be made in your input file rather than in each test.
Updating many tests or samplers **can be time consuming** but because a JMeter test is just XML you can make updates to
your test in an automated way by parsing the XML and updating in code.

In this post we are going to look at how we can do this as well as discussing techniques that you should be adopting
should you wish to use this process to update your tests. If you want to follow along the JMeter project and java code
can be <a href="https://blog.octoperf.com/img/blog/update-jmeter-script-xml-parser/octoperf-test-parser.zip" download>found here</a>.

## Using an Integrated Development Environment (IDE)

In order to write the code to parse and update your JMeter tests you are going to need a Integrated Development
Environment (IDE), for the purposes of this post we are going to
use [IntelliJ](https://www.jetbrains.com/help/idea/discover-intellij-idea.html "IntelliJ"). The community edition of
IntelliJ can be downloaded and used for free from [here](https://www.jetbrains.com/idea/download/ "here"). We are going
to use Java to write our parser so when creating a new project make sure it is a Java project.

![New Java Project](https://blog.octoperf.com/img/blog/update-jmeter-script-xml-parser/intellij-new-project.png)

## Building a dummy test

We will now build a test for us to parse which will include:

* 4 samplers
* 2 pre-processors
* 1 post-processor
* Query parameters

![Test Plan Overview](https://blog.octoperf.com/img/blog/update-jmeter-script-xml-parser/test-plan-overview.png)

We have included a number of different elements to the test to show how each one can be updated using a XML parser.

Let’s look at each sampler to see the data they contain.

![Sampler 1](https://blog.octoperf.com/img/blog/update-jmeter-script-xml-parser/sampler-1.png)

![Sampler 1 PreProcessor](https://blog.octoperf.com/img/blog/update-jmeter-script-xml-parser/sampler-1-pre-processor.png)

![Sampler 2](https://blog.octoperf.com/img/blog/update-jmeter-script-xml-parser/sampler-2.png)

![Sampler 2 PreProcessor](https://blog.octoperf.com/img/blog/update-jmeter-script-xml-parser/sampler-2-pre-processor.png)

![Sampler 3](https://blog.octoperf.com/img/blog/update-jmeter-script-xml-parser/sampler-3.png)

![Sampler 3 PostProcessor](https://blog.octoperf.com/img/blog/update-jmeter-script-xml-parser/sampler-3-post-processor.png)

![Sampler 4](https://blog.octoperf.com/img/blog/update-jmeter-script-xml-parser/sampler-4.png)

We’ll look at them in more detail and discuss how we will update these later in the post.

## Simple parsing of test

To start with let’s look at how we might start parsing this test. We will start by creating a directory called script in
our IntelliJ project and copying our test we have created into this directory.

![Copy Script](https://blog.octoperf.com/img/blog/update-jmeter-script-xml-parser/copy-script-intellij.png)

We can see that our test is displayed as [XML](https://en.wikipedia.org/wiki/XML "XML"). We are now going to create
a [Java Class](https://www.w3schools.com/java/java_classes.asp "Java Class") under the Java directory called
ExtractJMeterTestDetails.

![Empty Class](https://blog.octoperf.com/img/blog/update-jmeter-script-xml-parser/empty-class.png)

Let’s build a very simple [parser](https://www.w3schools.com/xml/xml_parser.asp "parser") to return the top level nodes
in the JMeter test. Here is the Java code:

```java
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.File;
import java.io.IOException;

public class ExtractJMeterTestDetails {

    public static void main(String[] args) throws ParserConfigurationException, IOException, SAXException {

        // Instantiate the Factory
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();

        // Create document builder
        DocumentBuilder db = dbf.newDocumentBuilder();

        // Load the test from the script directory
        Document doc = db.parse(new File("script/octoperf-test-parser.jmx"));

        // Optional, but recommended
        doc.getDocumentElement().normalize();

        // Get the top level node and iterate all nodes
        NodeList topLevelNodeList = doc.getElementsByTagName("**");
        for (int i = 0; i < topLevelNodeList.getLength(); i++) {
            System.out.println(topLevelNodeList.item(i).getNodeName());
        }
    }
}
```

Let’s pick out the main parts from this code

What we are doing here is loading the test into a document

``` Document doc = db.parse(new File("script/octoperf-test-parser.jmx"));```

Getting all the top level nodes and iterating through them

```java
NodeList topLevelNodeList = doc.getElementsByTagName("**");
        for (int i = 0; i < topLevelNodeList.getLength(); i++) {
            System.out.println(topLevelNodeList.item(i).getNodeName());
        }
```

If we run this, we see in the output console a list of all the nodes at the top level of our test.

![Script Execution](https://blog.octoperf.com/img/blog/update-jmeter-script-xml-parser/first-script-execution.png)

Now this is **not particularly useful yet**, but it demonstrates that we can load the test and access all the nodes.
Let’s make some updates to the code. In our for-loop above we replace the System.out.println() method call with

```java
Node nodeTop = topLevelNodeList.item(i);
NodeList nodeChildren = nodeTop.getChildNodes();
for(int a=0; a < nodeChildren.getLength(); a++) {
    Node node = nodeChildren.item(a);
    System.out.println(node.getNodeName());
}
```

So, for each of the top-level nodes we are now getting their children and outputting these. Let’s run this again.

![Script Execution](https://blog.octoperf.com/img/blog/update-jmeter-script-xml-parser/second-script-execution.png)

Again, this is not particularly useful, but we now have visibility of all the nodes in the test. Let’s now **make our
code more useful** and look at outputting something meaningful. If we look at one of
the [HTTP Samplers](https://jmeter.apache.org/usermanual/component_reference.html#HTTP_Request "HTTP Samplers") in XML
we see:

![Sampler 1](https://blog.octoperf.com/img/blog/update-jmeter-script-xml-parser/http-sampler-1.png)

So, we can see the structure of the HTTPSampler. Let’s update our parser to only look for HTTPSamplerProxy nodes and get
the attributes from each of these nodes, we will then iterate through the attributes and output to the console. We will
add this code to our parser, this goes in the location the System.out.println() method call from above was located.

```java
if(node.getNodeName().equals("HTTPSamplerProxy")) {
    NamedNodeMap samplerMainAttributes = node.getAttributes();
    for (int j = 0; j < samplerMainAttributes.getLength(); j++) {
            System.out.println("NODE-NAME: " + samplerMainAttributes.item(j).getNodeName());
            System.out.println("NODE-VALUE: " +samplerMainAttributes.item(j).getNodeValue());
    }
}
```

If you are not sure where this fits in to the code, you can find the full class code <a href="https://blog.octoperf.com/img/blog/update-jmeter-script-xml-parser/octoperf-test-parser.zip" download>here</a>. Let’s run
our parser again:

![Script Execution](https://blog.octoperf.com/img/blog/update-jmeter-script-xml-parser/third-script-execution.png)

We are now starting to return meaningful data from our test, we can see for each sampler we are returning the
attributes. If we go back and look at the test we can see there are a number
of [stringProp](https://jmeter.apache.org/api/org/apache/jmeter/testelement/property/StringProperty.html "stringProp")
and [boolProp](https://jmeter.apache.org/api/org/apache/jmeter/testelement/property/BooleanProperty.html "boolProp")
nodes that contain the server and request details in their attributes.

![Sampler 1](https://blog.octoperf.com/img/blog/update-jmeter-script-xml-parser/http-sampler-1.png)

What we need to do now is get the child nodes of the sampler and iterate through them and for each node we get the
attributes and check for these:

> HTTPSampler.domain
> HTTPSampler.path
> HTTPSampler.port
> HTTPSampler.protocol
> HTTPSampler.method

When we find them, we print the values to the console. If we add this code to our parser:

```java
NodeList childNodes = node.getChildNodes();
for (int k = 0; k < childNodes.getLength(); k++) {
    if (childNodes.item(k).hasAttributes()) {
        NamedNodeMap samplerChildAttributes = childNodes.item(k).getAttributes();
        for (int l = 0; l < samplerChildAttributes.getLength(); l++) {
            if (samplerChildAttributes.item(l).getNodeName().equals("name")) {
                if (samplerChildAttributes.item(l).getNodeValue().equals("HTTPSampler.domain")) {
                    System.out.println("Server Name of IP = " + childNodes.item(k).getTextContent());
                }
                if (samplerChildAttributes.item(l).getNodeValue().equals("HTTPSampler.path")) {
                    System.out.println("Path = " +childNodes.item(k).getTextContent());
                }
                if (samplerChildAttributes.item(l).getNodeValue().equals("HTTPSampler.port")) {
                    System.out.println("Port Number = " + childNodes.item(k).getTextContent());
                }
                if (samplerChildAttributes.item(l).getNodeValue().equals("HTTPSampler.protocol")) {
                    System.out.println("Protocol = " + childNodes.item(k).getTextContent());
                }
                if (samplerChildAttributes.item(l).getNodeValue().equals("HTTPSampler.method")) {
                    System.out.println("Method = " + childNodes.item(k).getTextContent());
                }
            }
        }
    }
}
```

Let’s execute the parser:

![Script Execution](https://blog.octoperf.com/img/blog/update-jmeter-script-xml-parser/fourth-script-execution.png)

As you can see, we are now **extracting all the details** of each sampler.

## Sampler Pre and Post Processors

Now we can parse our Test XML and pick out each sampler let’s look at how we can extract the **pre and post processor**
data and the parameters we added in **sampler_4**. We will start with the **pre-processors** and **post-processors** we
added in **sampler_1**, **sampler_2** and **sampler_3** as these follow a similar pattern and then we will look at the
parameters in **sampler_4** afterwards.

We have already looked at the XML for **sampler_1** but in order to see the **pre-processor** associated with it we need
to look outside of the **HTTPSamplerProxy** that we have been looking at so far.

![Sampler 1 PreProcessor](https://blog.octoperf.com/img/blog/update-jmeter-script-xml-parser/http-sampler-1-plus-extra.png)

We can see
the [JSR223PreProcessor](https://jmeter.apache.org/usermanual/component_reference.html#JSR223_PreProcessor "JSR223PreProcessor")
node which sits outside of the **HTTPSamplerProxy** node but grouped together by an encompassing **HashTree** node. This
is the same for all the **sampler_2** and **sampler_3** so we will look at extracting data from **sampler_1** as part of
this blog post as you should be able to use the same techniques to extract data from the others.

We are now going to **create another Java Class** under the Java directory called **ExtractJMeterPreProcessorDetails**,
if we copy the existing one, we have already created we will have all the foundation work we have done. What we are
going to do is remove the block of code we added to grab the details of the **HTTPSamplerProxy** node leaving us with
this.

```java
public class ExtractJMeterPreProcessorDetails {

    public static void main(String[] args) throws ParserConfigurationException, IOException, SAXException {

        // Instantiate the Factory
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();

        // Create document builder
        DocumentBuilder db = dbf.newDocumentBuilder();

        // Load the test from the script directory
        Document doc = db.parse(new File("script/octoperf-test-parser.jmx"));

        // Optional, but recommended
        doc.getDocumentElement().normalize();

        // Get the top level node and iterate all nodes
        NodeList topLevelNodeList = doc.getElementsByTagName("**");
        for (int i = 0; i < topLevelNodeList.getLength(); i++) {
            Node nodeTop = topLevelNodeList.item(i);
            NodeList nodeChildren = nodeTop.getChildNodes();
            for(int a=0; a < nodeChildren.getLength(); a++) {
                Node node = nodeChildren.item(a);
                if(node.getNodeName().equals("HTTPSamplerProxy")) {
                    NamedNodeMap samplerMainAttributes = node.getAttributes();
                    for (int j = 0; j < samplerMainAttributes.getLength(); j++) {
                        if(samplerMainAttributes.item(j).getNodeName().equals("testname")) {
                            System.out.println("Sampler Name = " + samplerMainAttributes.item(j).getNodeValue());
                        }
                    }
                    System.out.println("------------------------------------------");
                }
            }
        }
    }
}
```

This is basically searching for all the **HTTPSamplerProxy** nodes and outputting their name to the console.

We know that the **JSR223PreProcessor** node it at the same level as the **HTTPSamplerProxy** node therefore we can add
some code to grab this as it’s a case of searching for the **JSR223PreProcessor** nodes in the test.

Remember there is only one **JSR223PreProcessor** node as the ones in **sampler_2** and **sampler_3**
are [JDBCPreProcessor](https://jmeter.apache.org/usermanual/component_reference.html#JDBC_PreProcessor "JDBCPreProcessor")
and [RegexExtractor](https://jmeter.apache.org/usermanual/component_reference.html#RegEx_User_Parameters "RegexExtractor")
so we will include these in our parser code as well. This is the code we are adding:

```java
if(node.getNodeName().equals("JSR223PreProcessor")) {
    NamedNodeMap samplerMainAttributes = node.getAttributes();
    for (int j = 0; j < samplerMainAttributes.getLength(); j++) {
        if (samplerMainAttributes.item(j).getNodeName().equals("testname")) {
            System.out.println("PreProcessor Name = " + samplerMainAttributes.item(j).getNodeValue());
        }
    }
}
if(node.getNodeName().equals("JDBCPreProcessor")) {
    NamedNodeMap samplerMainAttributes = node.getAttributes();
    for (int j = 0; j < samplerMainAttributes.getLength(); j++) {
        if (samplerMainAttributes.item(j).getNodeName().equals("testname")) {
            System.out.println("PreProcessor Name = " + samplerMainAttributes.item(j).getNodeValue());
        }
    }
}
if(node.getNodeName().equals("RegexExtractor")) {
    NamedNodeMap samplerMainAttributes = node.getAttributes();
    for (int j = 0; j < samplerMainAttributes.getLength(); j++) {
        if(samplerMainAttributes.item(j).getNodeName().equals("testname")) {
            System.out.println("PostProcessor Name = " + samplerMainAttributes.item(j).getNodeValue());
        }
    }
    System.out.println("------------------------------------------");
}
```

As before, if you are not sure where this fits in to the code, you can find the full class code <a href="https://blog.octoperf.com/img/blog/update-jmeter-script-xml-parser/octoperf-test-parser.zip" download>here</a>.

Let’s execute the parser again:

![Script Execution](https://blog.octoperf.com/img/blog/update-jmeter-script-xml-parser/fifth-script-execution.png)

We can see that the samplers and the pre and post processor names have been captured and written to the console. As
discussed above we will look at extracting the values from **sampler_1** as the techniques for **sampler_2** and **
sampler_3** is the same. We are going to use a similar process to that used in the first Java Class file we created to
get the values from the **sampler_1** **JSR223PreProcessor** node.

We will add this code to our parser:

```java
NodeList childNodes = node.getChildNodes();
for (int k = 0; k < childNodes.getLength(); k++) {
    if (childNodes.item(k).hasAttributes()) {
        NamedNodeMap samplerChildAttributes = childNodes.item(k).getAttributes();
        for (int l = 0; l < samplerChildAttributes.getLength(); l++) {
            if (samplerChildAttributes.item(l).getNodeName().equals("name")) {
                if (samplerChildAttributes.item(l).getNodeValue().equals("script")) {
                    System.out.println("Script = " + childNodes.item(k).getTextContent());
                }
            }
        }
    }
}
```

Which is a case of us getting all the child nodes under the **JST223PreProcessor** and extracting the details of the
script by iterating over all the children.

If we run our parser.

![Script Execution](https://blog.octoperf.com/img/blog/update-jmeter-script-xml-parser/sixth-script-execution.png)

We can see that we have captured the script we entered in our sampler when we created the JMeter test.

## Sampler Parameters

We will now look at how we would capture the parameters we added into **sampler_4** as this uses a different technique
and then we can look at how we might update these values in the test using the parser. Let’s take a look more closely
at **sampler_4** in the XML.

![Sampler 4 Parameters](https://blog.octoperf.com/img/blog/update-jmeter-script-xml-parser/http-sampler-4-plus-extra.png)

We can see that the parameter we added to the sampler is under
a [elementProp](https://jmeter.apache.org/api/org/apache/jmeter/testelement/property/MapProperty.html "elementProp")
node where there is
a [collectionProp](https://jmeter.apache.org/api/org/apache/jmeter/testelement/property/CollectionProperty.html "collectionProp")
which is where we would see all our parameters if we had added more. Under the collectionProp there is the parameter we
created along with the value we gave the parameter.

Let’s make **some changes to the code** to capture the parameter data. To do this we will again make a copy of the class
file and call this one **ExtractJMeterParameterDetails**, the full class file
is <a href="https://blog.octoperf.com/img/blog/update-jmeter-script-xml-parser/octoperf-test-parser.zip" download>available here</a>. We will,
like last time leave the code that gets us to iterate the **HTTPSamplerProxy** nodes and then add the following code.

```java
if(node.getNodeName().equals("HTTPSamplerProxy")) {
    NamedNodeMap samplerMainAttributes = node.getAttributes();
    for (int j = 0; j < samplerMainAttributes.getLength(); j++) {
        if(samplerMainAttributes.item(j).getNodeName().equals("testname")) {
            if(samplerMainAttributes.item(j).getNodeValue().equals("sampler_4")) {
                NodeList childNodes = node.getChildNodes();
                for (int k = 0; k < childNodes.getLength(); k++) {
                    if(childNodes.item(k).getNodeName().equals("elementProp")) {
                        NodeList childchildNodes = childNodes.item(k).getChildNodes();
                        for (int l = 0; l < childchildNodes.getLength(); l++) {
                            if(childchildNodes.item(l).getNodeName().equals("collectionProp")) {
                                NodeList childchildchildNodes = childchildNodes.item(l).getChildNodes();
                                for (int m = 0; m < childchildchildNodes.getLength(); m++) {
                                    if(childchildchildNodes.item(m).getNodeName().equals("elementProp")) {
                                        if (childchildchildNodes.item(m).hasAttributes()) {
                                            NamedNodeMap samplerChildAttributes = childchildchildNodes.item(m).getAttributes();
                                            for (int n = 0; n < samplerChildAttributes.getLength(); n++) {
                                                if (samplerChildAttributes.item(n).getNodeName().equals("name")) {
                                                    System.out.println("Parameter = " + samplerChildAttributes.item(n).getNodeValue());
                                                    NodeList childchildchildchildNodes = childchildchildNodes.item(m).getChildNodes();
                                                    for (int o = 0; o < childchildchildchildNodes.getLength(); o++) {
                                                        if (childchildchildchildNodes.item(o).hasAttributes()) {
                                                            NamedNodeMap elementChildAttributes = childchildchildchildNodes.item(o).getAttributes();
                                                            for (int p = 0; p < elementChildAttributes.getLength(); p++) {
                                                                if (elementChildAttributes.item(p).getNodeValue().equals("Argument.value")) {
                                                                    System.out.println("Value = " + childchildchildchildNodes.item(o).getTextContent());
                                                                }
                                                            }
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```

There are **more elegant ways to recursively iterate through the nodes**, but we wanted to show you how you must drill
into each node and extract the information you need through a series of node and attribute checks. If we execute the
parser:

![Script Execution](https://blog.octoperf.com/img/blog/update-jmeter-script-xml-parser/seventh-script-execution.png)

You can see that we have captured the parameter values.

## Updating our tests

The purpose of this blog post was to show you how you could update tests using a parser written in Java in order to save
you time if you needed to make updates to many tests and so far, we have not looked at this at all. We have in fact done
all the hard work already as updating the values we have captured is easy.

Let’s take our first example where we listed out the
> Server Name or IP
> Port Number
> Protocol
> Path
> Method

If you remember the part of the class that captured the data was:

```java
if (samplerChildAttributes.item(l).getNodeName().equals("name")) {
    if (samplerChildAttributes.item(l).getNodeValue().equals("HTTPSampler.domain")) {
        System.out.println("Server Name of IP = " + childNodes.item(k).getTextContent());
    }
    if (samplerChildAttributes.item(l).getNodeValue().equals("HTTPSampler.path")) {
        System.out.println("Path = " +childNodes.item(k).getTextContent());
    }
    if (samplerChildAttributes.item(l).getNodeValue().equals("HTTPSampler.port")) {
        System.out.println("Port Number = " + childNodes.item(k).getTextContent());
    }
    if (samplerChildAttributes.item(l).getNodeValue().equals("HTTPSampler.protocol")) {
        System.out.println("Protocol = " + childNodes.item(k).getTextContent());
    }
    if (samplerChildAttributes.item(l).getNodeValue().equals("HTTPSampler.method")) {
        System.out.println("Method = " + childNodes.item(k).getTextContent());
    }
}
```

Where we were iterating the child nodes and their attributes. In order to update these values, we simply use the **
setTextContent** method rather than the **getTextContext** method and we need to save the document in order to persist
the data. Let’s start by updating the node value of all the **HTTPSampler.port** values, they currently vary depending
on the sampler and are set to

> /api/test_enpoint/service_1
> /api/test_enpoint/service_2
> /api/test_enpoint/service_3
> /api/test_enpoint/service_4

What we will do is replace **/test_endpoint/** with **/new_test_endpoint/** in all samplers. We do this by making this
change in the code:

```java
if (samplerChildAttributes.item(l).getNodeValue().equals("HTTPSampler.path")) {
    String currentPath = childNodes.item(k).getTextContent();
    childNodes.item(k).setTextContent(currentPath.replace("test_endpoint", "new_test_endpoint"));
    System.out.println("Path = " + childNodes.item(k).getTextContent());
}
```

So, we are capturing the current value and then replacing the string while setting the new value. We are doing the **
transformation of the node**, but we need to save the updated XML. We do this by using the **TransformerFactory** to
create a new version of the XML in the same location as the original.

We use this code:

```java
// Create a new test from the updated XML
TransformerFactory factory = TransformerFactory.newInstance();
Transformer transformer = factory.newTransformer();

DOMSource source = new DOMSource(doc);
StreamResult result = new StreamResult(new File("script/octoperf-test-parser-new.jmx"));
transformer.transform(source, result);
```

If we run the parser:

![Sampler 1 Write To File](https://blog.octoperf.com/img/blog/update-jmeter-script-xml-parser/http-sampler-1-after-change.png)

We can see we have a new test and the **HTTPSampler.path** value has been set to new_test_endpoint. We will do one more
change as the approach is the same regardless of the sampler and regardless of whether you are updating the value of a
node or one of its attributes. This time we will **replace a value with a property value** so we can pass this in from
either a properties file or on the command line, this will obviously mean that you can handle any changes to static
values outside of the test and not need to make updates by parsing the XML in the future.

What we will look to do is update the Server Name of IP field with a property, we’ll do that for all samplers. We’ll
update the section where we get the **HTTPSampler.domain** with this code.

```java
if (samplerChildAttributes.item(l).getNodeValue().equals("HTTPSampler.domain")) {
    childNodes.item(k).setTextContent("$P{__(serverName)}");
    System.out.println("Server Name of IP = " + childNodes.item(k).getTextContent());
}
```

Where we will set the value of the Server Name of IP to be `$P{__(serverName)}`. We’ll delete the new test file we
created and run our parser again.

![Sampler 1 Write To File With Parameter](https://blog.octoperf.com/img/blog/update-jmeter-script-xml-parser/http-sampler-1-after-second-change.png)

We can now see that **HTTPSampler.domain** value has been updated. Just for completeness we will open up the test in
JMeter and check the values of the sampler.

![JMeter Test After Changes](https://blog.octoperf.com/img/blog/update-jmeter-script-xml-parser/http-sampler-1-after-second-change-script.png)

We can see our two changes we have made.

## Making multiple updates

If you had **one test to update** you may feel that doing this manually would probably be the most effective way of
doing this. But if you need to **update multiple tests** then this may be a good option.

We will finish this post by looking at how you can wrap your code in a loop to iterate over more than one file in the
script directory that we created and that currently contains our single test. If we duplicate our test in the scripts
directory:

![JMeter Multiple Tests](https://blog.octoperf.com/img/blog/update-jmeter-script-xml-parser/multiple-tests.png)

We will now update the first java class we created ExtractJMeterTestDetails to loop through the tests. If we use this
code as an addition to our class file:

```java
File dir = new File("script");
File[] directoryListing = dir.listFiles();
if (directoryListing != null) {
    for (File child : directoryListing) {
        System.out.println(child.getName());
    }
}
```

We see that this will iterate over the files in the script folder. If we execute our parser:

![Script Execution](https://blog.octoperf.com/img/blog/update-jmeter-script-xml-parser/eighth-script-execution.png)

We see that we have listed the files in the script folder, if you place this around the code we have already written to
parse the XML it will iterate over them.

## Conclusion

Hopefully we have shown you how you could make multiple updates to you JMeter performance tests should you have many
static values that need updating. Once you know how to **manipulate your JMeter tests programmatically** you may find
other uses for the techniques we have looked at in this blog post.
