Extract the contents of an xml node without node into a variable in jmeter

In my JMeter script, I am testing SOAP web services. I send the initial request to webservice S1 and then use the response from it to build the request on S2. The answer from S1 is presented as:

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> <soap:Body> <s:response xmlns:s="http://custom.namespace.com/namespace"> ... <s:responseDetails> <s:detail1>some info</s:detail> <s:detail2>another info<s:detail2> ... </s:responseDetails> </s:response> </soap:Body> </soap:Envelope> 

I need to use everything inside <s:responseDetails> to create a request in S2, but wrapped in another xml element:

 <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:s="http://custom.namespace.com/namespace"> <soap:Body> <s:request> <s:details> <s:detail1>some info</s:detail> <s:detail2>another info<s:detail2> ... </s:details> </s:request> </soap:Body> </soap:Envelope> 

Notice the <s:details> element in the request instead of <s:responseDetails> .

I started with an XPath extractor, hoping to use an XPath expression to put everything under the <s:responseDetails> in a JMeter variable:

  • //*[local-name()='responseDetails']/node() - gives me a set of JMeter variables with different <s:responseDetails> children, while I want them to be in the same variable
  • //*[local-name()='responseDetails'] - gives me the whole node <s:responseDetails> , which I cannot use due to the root tag <s:responseDetails> , which I need to replace with <s:details>

What is the correct expression to get everything inside <s:responseDetails> into a variable so that you can use it later

 <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:s="http://custom.namespace.com/namespace"> <soap:Body> <s:request> <s:details> ${details} </s:details> </s:request> </soap:Body> </soap:Envelope> 

Or maybe there is another way to solve my problem?

+4
source share
2 answers

Follow these steps:

1) Add XPath Extractor as you did:

  • Reference Name: responseFragment
  • XPath request: // s: response / s: responseDetails
  • Use namespaces = true

2) Add a Beanshell sampler with:

 String fragment = vars.get("responseFragment"); // Improve this replacement by regexp to avoid side effects String newFragment = fragment.replace("responseDetails","details"); vars.put("modifiedFragment", newFragment); 

3) Then use: $ {modifiedFragment}

Note that a Beanshell sampler will slightly degrade JMeter, but it should be reasonable.

Note that you can replace the Beanshell sampler with JSR 223 with the groovy base language and script in an external file.

Using JMeter> version 2.7 will be better than beanshell because the new version of JMeter introduces a new caching mechanism that will β€œcompile” the groovy script and make it almost as efficient as the Java class.

As of September 3, 2012, this mechanism is available in the JMeter Nightly build .

JMeter Test Plan Example:

  <?xml version="1.0" encoding="UTF-8"?> <jmeterTestPlan version="1.2" properties="2.3" jmeter="2.8-SNAPSHOT.20120903"> <hashTree> <TestPlan guiclass="TestPlanGui" testclass="TestPlan" testname="Test Plan" enabled="true"> <stringProp name="TestPlan.comments"></stringProp> <boolProp name="TestPlan.functional_mode">false</boolProp> <boolProp name="TestPlan.serialize_threadgroups">false</boolProp> <elementProp name="TestPlan.user_defined_variables" elementType="Arguments" guiclass="ArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true"> <collectionProp name="Arguments.arguments"/> </elementProp> <stringProp name="TestPlan.user_define_classpath"></stringProp> </TestPlan> <hashTree> <ThreadGroup guiclass="ThreadGroupGui" testclass="ThreadGroup" testname="Thread Group" enabled="true"> <stringProp name="ThreadGroup.on_sample_error">continue</stringProp> <elementProp name="ThreadGroup.main_controller" elementType="LoopController" guiclass="LoopControlPanel" testclass="LoopController" testname="Loop Controller" enabled="true"> <boolProp name="LoopController.continue_forever">false</boolProp> <stringProp name="LoopController.loops">1</stringProp> </elementProp> <stringProp name="ThreadGroup.num_threads">1</stringProp> <stringProp name="ThreadGroup.ramp_time">1</stringProp> <longProp name="ThreadGroup.start_time">1346673693000</longProp> <longProp name="ThreadGroup.end_time">1346673693000</longProp> <boolProp name="ThreadGroup.scheduler">false</boolProp> <stringProp name="ThreadGroup.duration"></stringProp> <stringProp name="ThreadGroup.delay"></stringProp> </ThreadGroup> <hashTree> <JavaSampler guiclass="JavaTestSamplerGui" testclass="JavaSampler" testname="Java Request" enabled="true"> <elementProp name="arguments" elementType="Arguments" guiclass="ArgumentsPanel" testclass="Arguments" enabled="true"> <collectionProp name="Arguments.arguments"> <elementProp name="Sleep_Time" elementType="Argument"> <stringProp name="Argument.name">Sleep_Time</stringProp> <stringProp name="Argument.value">100</stringProp> <stringProp name="Argument.metadata">=</stringProp> </elementProp> <elementProp name="Sleep_Mask" elementType="Argument"> <stringProp name="Argument.name">Sleep_Mask</stringProp> <stringProp name="Argument.value">0xFF</stringProp> <stringProp name="Argument.metadata">=</stringProp> </elementProp> <elementProp name="Label" elementType="Argument"> <stringProp name="Argument.name">Label</stringProp> <stringProp name="Argument.value">OK</stringProp> <stringProp name="Argument.metadata">=</stringProp> </elementProp> <elementProp name="ResponseCode" elementType="Argument"> <stringProp name="Argument.name">ResponseCode</stringProp> <stringProp name="Argument.value">200</stringProp> <stringProp name="Argument.metadata">=</stringProp> </elementProp> <elementProp name="ResponseMessage" elementType="Argument"> <stringProp name="Argument.name">ResponseMessage</stringProp> <stringProp name="Argument.value">200</stringProp> <stringProp name="Argument.metadata">=</stringProp> </elementProp> <elementProp name="Status" elementType="Argument"> <stringProp name="Argument.name">Status</stringProp> <stringProp name="Argument.value">OK</stringProp> <stringProp name="Argument.metadata">=</stringProp> </elementProp> <elementProp name="SamplerData" elementType="Argument"> <stringProp name="Argument.name">SamplerData</stringProp> <stringProp name="Argument.value"></stringProp> <stringProp name="Argument.metadata">=</stringProp> </elementProp> <elementProp name="ResultData" elementType="Argument"> <stringProp name="Argument.name">ResultData</stringProp> <stringProp name="Argument.value">&lt;soap:Envelope xmlns:soap=&quot;http://schemas.xmlsoap.org/soap/envelope/&quot;&gt; &lt;soap:Body&gt; &lt;s:response xmlns:s=&quot;http://custom.namespace.com/namespace&quot;&gt; &lt;s:responseDetails&gt; &lt;s:detail1&gt;some info&lt;/s:detail1&gt; &lt;s:detail2&gt;another info&lt;/s:detail2&gt; &lt;/s:responseDetails&gt; &lt;/s:response&gt; &lt;/soap:Body&gt; &lt;/soap:Envelope&gt;</stringProp> <stringProp name="Argument.metadata">=</stringProp> </elementProp> </collectionProp> </elementProp> <stringProp name="classname">org.apache.jmeter.protocol.java.test.JavaTest</stringProp> </JavaSampler> <hashTree> <XPathExtractor guiclass="XPathExtractorGui" testclass="XPathExtractor" testname="XPath Extractor" enabled="true"> <stringProp name="XPathExtractor.default"></stringProp> <stringProp name="XPathExtractor.refname">TOTO</stringProp> <stringProp name="XPathExtractor.xpathQuery">//s:response/s:responseDetails</stringProp> <boolProp name="XPathExtractor.validate">false</boolProp> <boolProp name="XPathExtractor.tolerant">false</boolProp> <boolProp name="XPathExtractor.namespace">true</boolProp> <boolProp name="XPathExtractor.whitespace">true</boolProp> </XPathExtractor> <hashTree/> </hashTree> <DebugSampler guiclass="TestBeanGUI" testclass="DebugSampler" testname="Debug Sampler" enabled="true"> <boolProp name="displayJMeterProperties">false</boolProp> <boolProp name="displayJMeterVariables">true</boolProp> <boolProp name="displaySystemProperties">false</boolProp> </DebugSampler> <hashTree/> <ResultCollector guiclass="ViewResultsFullVisualizer" testclass="ResultCollector" testname="View Results Tree" enabled="true"> <boolProp name="ResultCollector.error_logging">false</boolProp> <objProp> <name>saveConfig</name> <value class="SampleSaveConfiguration"> <time>true</time> <latency>true</latency> <timestamp>true</timestamp> <success>true</success> <label>true</label> <code>true</code> <message>false</message> <threadName>true</threadName> <dataType>false</dataType> <encoding>false</encoding> <assertions>true</assertions> <subresults>false</subresults> <responseData>false</responseData> <samplerData>false</samplerData> <xml>false</xml> <fieldNames>false</fieldNames> <responseHeaders>false</responseHeaders> <requestHeaders>false</requestHeaders> <responseDataOnError>false</responseDataOnError> <saveAssertionResultsFailureMessage>false</saveAssertionResultsFailureMessage> <assertionsResultsToSave>0</assertionsResultsToSave> <bytes>true</bytes> <hostname>true</hostname> <threadCounts>true</threadCounts> <sampleCount>true</sampleCount> </value> </objProp> <stringProp name="filename"></stringProp> </ResultCollector> <hashTree/> </hashTree> </hashTree> </hashTree> </jmeterTestPlan> 

Another way:

1) Add XPath Extractor as you did:

  • Reference Name: responseFragment
  • XPath request: // s: response / s: responseDetails / *
  • Use namespaces = true

2) Add a Beanshell sampler with:

 int number = Integer.parseInt(vars.get("fullAnswer_matchNr")); StringBuilder builder = new StringBuilder(); for(int i=0;i<number;i++) { builder.append(vars.get("fullAnswer_"+(i+1))); } vars.put("body", builder.toString()); 

3) use the body

It's a little cleaner as there is no replacement

+4
source

Could you omit the <s:details> and send the request as follows:

 <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:s="http://custom.namespace.com/namespace"> <soap:Body> <s:request> ${details} </s:request> </soap:Body> </soap:Envelope> 
0
source

Source: https://habr.com/ru/post/1432049/


All Articles