skip to Main Content

Given XML file snippet is:

<?xml version="1.0" standalone="yes"?>
<event_configuration family="21" version="2">
    <pqr subtype="abc">
    <event val="73002" name="$MyCpu"> </event>
    <event val="73003" name="$MyCpuKernel"> </event>

    <metric name="Ratio" expression="$MyCpuKernel / $MyCpu"> </metric>
    </pqr>
</event_configuration>

I have parsed this xml file using "ElementTree" library in Python, please find the code below:

    def parse_xml_to_json(self):
        data = {'metric': []}
        root = ET.fromstring(self.xml_file)

        for element in root.findall('.//*'):
            element_type = element.tag
            if element_type not in ["pqr", "stu", "vwx"]:
                continue
            subtype_name = element.attrib['subtype']
            event_map = {}
            for event in element.findall('.//event'):
                event_name = event.attrib['name']
                val_value = event.attrib['val']
                event_map[event_name] = val_value

            for metric in element.findall('metric'):
                expression = metric.attrib['expression']
                metric_name = metric.attrib['name']
          
                for event_name, val_value in event_map.items():
                    expression = expression.replace(event_name, val_value)

                data['metric'].append({
                    'Name': metric_name,
                    'Expression': expression,
                    'Type': element_type
                })

        return data

I am getting the output, but this code is unable to replace the event name present inside "Expression" with the val_value as shown below:-

Output:

{
"metric": [
    {
        "Name": "Ratio",
        "Expression": "73002Kernel / 73002",
        "Type": "pqr"
    },
    ....
    ....
]
}
    

Here, we can see in the "Expression" it should print "73003 / 73002".
I am unable to think of how to solve this issue. Is it possible to use regex here, how to apply it? Please suggest.

2

Answers


  1. You can change the XML and create than your JSON. The XML attribute values can be .get() and .set() For the expression attribute you can use an f-string with the values:

    Suggested solution in your code:

    import xml.etree.ElementTree as ET
    
    class Whatever:
        def __init__(self):
            self.xml_file = "eventConfig.xml"
        
        def parse_xml_to_json(self):
            data = {'metric': []}
            root = ET.parse(self.xml_file) # cahnged parse from file not from string
    
            for element in root.findall('.//*'):
                element_type = element.tag
                if element_type not in ["pqr", "stu", "vwx"]:
                    continue
                subtype_name = element.attrib['subtype']
                event_map = {}
                
                for metric in element.findall('metric'):
                    expression = metric.attrib['expression']
                    metric_name = metric.attrib['name']
    
                mycpu = root.find(".//event[@name = '$MyCpu']").get('val')
                mycpukernel = root.find(".//event[@name = '$MyCpuKernel']").get('val')
                tex = f"{mycpu}/{mycpukernel}"
                #metric = root.find(".//metric[@expression]").set('expression', tex)
    
                data['metric'].append({
                    'Name': metric_name,
                    'Expression': tex,
                    'Type': element_type
                })
    
            return data
        
    if __name__ == "__main__":
        p = Whatever()
        res = p.parse_xml_to_json()
        print(res)
    

    Output:

    {'metric': [{'Name': 'Ratio', 'Expression': '73002/73003', 'Type': 'pqr'}]}
    
    Login or Signup to reply.
  2. Here is an example how you can use re.sub to replace the values in expression:

    import re
    import xml.etree.ElementTree as ET
    
    
    def parse_xml_to_json(xml_file):
        data = {"metric": []}
        root = ET.fromstring(xml_file)
    
        for element in root.findall(".//*"):
            element_type = element.tag
            if element_type not in ["pqr", "stu", "vwx"]:
                continue
            subtype_name = element.attrib["subtype"]
            event_map = {}
            for event in element.findall(".//event"):
                event_name = event.attrib["name"]
                val_value = event.attrib["val"]
                event_map[event_name] = val_value
    
            for metric in element.findall("metric"):
                expression = metric.attrib["expression"]
                metric_name = metric.attrib["name"]
    
                for event_name, val_value in event_map.items():
                    expression = re.sub(
                        rf"{re.escape(event_name)}b", val_value, expression
                    )
    
                data["metric"].append(
                    {"Name": metric_name, "Expression": expression, "Type": element_type}
                )
    
        return data
    
    
    xml_file = """
    <?xml version="1.0" standalone="yes"?>
    <event_configuration family="21" version="2">
        <pqr subtype="abc">
        <event val="73002" name="$MyCpu"> </event>
        <event val="73003" name="$MyCpuKernel"> </event>
    
        <metric name="Ratio" expression="$MyCpuKernel / $MyCpu"> </metric>
        </pqr>
    </event_configuration>"""
    
    print(parse_xml_to_json(xml_file))
    

    Prints:

    {'metric': [{'Name': 'Ratio', 'Expression': '73003 / 73002', 'Type': 'pqr'}]}
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search