Search code examples
pythonxmlelementtree

How to update the value in a xml with sub child elements


I want to update the value of the 2 sub-child elements mentioned below from the given XML.

  1. <stringProp name="filename">language-preferences__GET.jtl</stringProp>
  2. <subresults>false</subresults>
</hashTree>
        <ResultCollector guiclass="ViewResultsFullVisualizer" testclass="ResultCollector" testname="View Results Tree" enabled="false">
          <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>true</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>true</fieldNames>
              <responseHeaders>false</responseHeaders>
              <requestHeaders>false</requestHeaders>
              <responseDataOnError>true</responseDataOnError>
              <saveAssertionResultsFailureMessage>true</saveAssertionResultsFailureMessage>
              <assertionsResultsToSave>0</assertionsResultsToSave>
              <bytes>true</bytes>
              <hostname>true</hostname>
              <threadCounts>true</threadCounts>
              <sampleCount>true</sampleCount>
            </value>
          </objProp>
          <stringProp name="filename"></stringProp>
        </ResultCollector>
        <hashTree/>
        <ResultCollector guiclass="StatVisualizer" testclass="ResultCollector" testname="Aggregate Report" 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>true</message>
              <threadName>true</threadName>
              <dataType>true</dataType>
              <encoding>false</encoding>
              <assertions>true</assertions>
              <subresults>false</subresults>
              <responseData>false</responseData>
              <samplerData>false</samplerData>
              <xml>false</xml>
              <fieldNames>true</fieldNames>
              <responseHeaders>false</responseHeaders>
              <requestHeaders>false</requestHeaders>
              <responseDataOnError>true</responseDataOnError>
              <saveAssertionResultsFailureMessage>true</saveAssertionResultsFailureMessage>
              <assertionsResultsToSave>0</assertionsResultsToSave>
              <bytes>true</bytes>
              <sentBytes>true</sentBytes>
              <url>true</url>
              <threadCounts>true</threadCounts>
              <idleTime>true</idleTime>
              <connectTime>true</connectTime>
            </value>
          </objProp>
          <stringProp name="filename">language-preferences__GET.jtl</stringProp>
        </ResultCollector>
        <hashTree/>

I have written the code below to reach the child elements of ResultCollector. However, I am not able figure out the better way of navigate through the multiple sub child elements.

    tree = ET.parse(jmx_path)
    aggregate_samplers = tree.findall('.//ResultCollector[@testname="Aggregate Report"]')
    active_aggregate_samplers = [active_aggregate_sampler for active_aggregate_sampler in aggregate_samplers
                                 if active_aggregate_sampler.attrib['enabled'] == 'true']
    for active_sampler in active_aggregate_samplers:
        for child in active_sampler:
            if child.tag == 'objProp':
                # < update **subresults** value as true>
            elif child.attrib['name'] == 'filename':
                child.text = str(uuid.uuid4()) + '_' + child.text // new file name
                # < update **filename** value as c82fa39b-5079-4838-b17c-fdf85f49fd5f_language-preferences__GET.jtl>

Solution

  • Note: Your example xml snippet has no root element!

    Answer: If the xml is correct you can find a list of your interested tags with findall(), see the doc. Than change the text or attribute content of the related list elements:

    import xml.etree.ElementTree as ET
    
    tree = ET.parse("hashTree.xml")
    root = tree.getroot()
    
    subres_list = root.findall(".//subresults")
    for subres in subres_list:
        subres.text = "true" # your new text for the list elements
    
    stringP_list = root.findall(".//stringProp")
    for stringP in stringP_list:
        stringP.text = "c82fa39b-5079-4838-b17c-fdf85f49fd5f_language-preferences__GET.jtl”
    

    You can also change individually tags of the list with the index(), e.g.:

    stringP_list[1].text = "new text" # use list index