Search code examples
jmeterbeanshell

How to let XPathExtractor extract xml element only if Http response code is 200?


In my JMeter test plan, I have a HttpRequest, I want to extract the link from its response only if the response code is 200. I can add an XPathExtractor post processor under HttpRequest and it works.

But I want to have an IfCondition first so that the extractor won't try to work on invalid content. But the IfController can't be added as a postprocessor.

Maybe I can have a BeanShell sampler to do it but I don't know how to use XPathExtractor in BeanShell.


Solution

    1. "Short and easy" way - use an additional Sampler

      • Add If Controller after the HTTP Request
      • Use ${JMeterThread.last_sample_ok} as "Condition"
      • Put Beanshell Sampler under the If Controller
      • Use the following code in Beanshell Sampler "Script" area:

        SampleResult.setResponseData(ctx.getPreviousResult().getResponseData());
        
      • Put XPath Extractor as a child of the Beanshell Sampler

      The above Beanshell script will return the same response as preceding HTTP Request sampler

      1. "Long and hard" way - extract XPath directly in Beanshell.

        • Put Beanshell PostProcessor instead of XPath Extractor
        • Use the following script as a reference:

          import org.apache.jmeter.util.PropertiesBasedPrefixResolver;
          import org.apache.jmeter.util.XPathUtil;
          import org.apache.xpath.XPathAPI;
          import org.apache.xpath.objects.XObject;
          import org.w3c.dom.Document;
          import org.w3c.dom.Element;
          import org.w3c.dom.Node;
          import org.w3c.dom.NodeList;
          import javax.xml.transform.OutputKeys;
          import javax.xml.transform.Transformer;
          import javax.xml.transform.TransformerFactory;
          import javax.xml.transform.dom.DOMSource;
          import javax.xml.transform.stream.StreamResult;
          
          
          InputStream in = new ByteArrayInputStream(prev.getResponseData());
          boolean useNameSpace = false;
          boolean isTolerant = true;
          boolean isQuiet = true;
          boolean showWarnings = true;
          boolean reportErrors = true;
          boolean isXML = false;
          boolean isDownloadDTDs = false;
          
          
          if (prev.isResponseCodeOK()) {
          
              InputStream in = new ByteArrayInputStream(prev.getResponseData());
              boolean useNameSpace = false;
              boolean isTolerant = true;
              boolean isQuiet = true;
              boolean showWarnings = true;
              boolean reportErrors = true;
              boolean isXML = false;
              boolean isDownloadDTDs = false;
          
          
              String query = "//a[text()='JMeter FAQ (Wiki)']";
              List matchStrings = new ArrayList();
              //matchStrings.add("-1");
              boolean returnFragment = false;
          
          
              Document doc = XPathUtil.makeDocument(in, false, false, useNameSpace, isTolerant, isQuiet, showWarnings, reportErrors
                          , isXML, isDownloadDTDs);
              String val = null;
              XObject xObject = XPathAPI.eval(doc, query, new PropertiesBasedPrefixResolver(doc.getDocumentElement());
              int objectType = xObject.getType();
              if (objectType == xObject.CLASS_NODESET) {
                  NodeList matches = xObject.nodelist();
                  int length = matches.getLength();
          
                  for (int i = 0; i < length; ++i) {
                      Node match = matches.item(i);
                      if (match instanceof Element) {
                          if (returnFragment) {
                              StringWriter sw = new StringWriter();
          
                              Transformer t = TransformerFactory.newInstance().newTransformer();
                                  t.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
                              t.transform(new DOMSource(match), new StreamResult(sw));
          
                              val = sw.toString();
                          } else {
                              Node firstChild = match.getFirstChild();
                              if (firstChild != null) {
                                  val = firstChild.getNodeValue();
                              } else {
                                  val = match.getNodeValue();
                              }
                          }
                      } else {
                          val = match.getNodeValue();
                      }
          
                      matchStrings.add(val);
                  }
              } else if (objectType != xObject.CLASS_NULL && objectType != xObject.CLASS_UNKNOWN && objectType != xObject.CLASS_UNRESOLVEDVARIABLE) {
                  val = xObject.toString();
                  matchStrings.add(val);
              } else {
                  log.warn("Unexpected object type: " + xObject.getTypeString() + " returned for: " + query);
              }
          
          
              for (String match : matchStrings) {
                  log.info("Match -----> " + match);
              }
          }
          

    See How to Use BeanShell: JMeter's Favorite Built-in Component guide for more information on using Beanshell in JMeter scripts