xml.py 3.6 KB
Newer Older
Dion Haefner's avatar
merge  
Dion Haefner committed
1 2
from __future__ import absolute_import

Dion Haefner's avatar
Dion Haefner committed
3 4 5 6 7 8 9 10
import xml.etree.ElementTree as ET
from warnings import warn
from collections import OrderedDict

from dorie.parscraper.warnings import XMLWarning
from dorie.parscraper.parameter import Parameter


11
def parse(filename,model=None):
Dion Haefner's avatar
Dion Haefner committed
12 13 14 15 16 17
    """
    Reads and parses a DORiE parameter XML file, using the :class:`xml.etree.ElementTree`
    package.

    The XML file is expected to have the following structure:

Dion Haefner's avatar
Dion Haefner committed
18
        :menuselection:`<dorie> --> <category name="..."> --> <parameter name="..."> --> (attributes)`
Dion Haefner's avatar
Dion Haefner committed
19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43

    Available attributes are all attributes of the :class:`dorie.parscraper.parameter.Parameter`
    class, except the ones starting with an underscore.

    :param str filename: Path to the input XML file
    :rtype: OrderedDict
    :return: all parsed category names as keys, and a list of all parameters in the\
    corresponding category as values (instances of :class:`Parameter`)
    :raises XMLWarning: if unknown, redundant, or malformatted XML elements are encountered

    """
    xml_tree = ET.parse(filename)
    root = xml_tree.getroot()

    xml_parameters = OrderedDict()
    for child in root:
        if child.tag != "category":
            warn("Unknown element {0}".format(child.tag),XMLWarning)
            continue
        if not "name" in child.attrib.keys():
            warn("Encountered category without proper 'name' attribute",XMLWarning)
            continue
        if not child.attrib["name"]:
            warn("Encountered category without proper 'name' attribute",XMLWarning)
            continue
44 45 46 47
        if model:
            category = model + "." + child.attrib["name"]    
        else:
            category = child.attrib["name"]
Dion Haefner's avatar
Dion Haefner committed
48 49 50 51 52 53 54 55 56 57 58 59 60 61
        category_parameters = []

        for grandchild in child:
            if grandchild.tag != "parameter":
                warn("Unknown element {0}".format(child.tag))
                continue
            if not "name" in grandchild.attrib.keys():
                warn("Encountered parameter without proper 'name' attribute",XMLWarning)
                continue
            if not grandchild.attrib["name"]:
                warn("Encountered parameter without proper 'name' attribute",XMLWarning)
                continue

            key = grandchild.attrib["name"]
62
            p = Parameter(model,category,key)
Dion Haefner's avatar
Dion Haefner committed
63

Dion Haefner's avatar
Dion Haefner committed
64 65 66 67 68
            if "hidden" in grandchild.attrib.keys():
                p.hidden = grandchild.attrib["hidden"].lower() in ["true","1","yes"]
            elif "hidden" in child.attrib.keys():
                p.hidden = child.attrib["hidden"].lower() in ["true","1","yes"]

Dion Haefner's avatar
Dion Haefner committed
69
            for attribute in grandchild:
70 71 72 73 74 75 76 77 78 79
                if hasattr(p, attribute.tag) and not attribute.tag.startswith("_"):
                    p_attr = getattr(p, attribute.tag)
                    stripped_text = attribute.text.lstrip().rstrip()
                    text_lines = [x.strip() for x in stripped_text.splitlines()]
                    if isinstance(p_attr, dict):
                        description = " ".join(text_lines)
                        p_attr[attribute.attrib["version"]] = description
                    else:
                        description = "\n".join(text_lines)
                        setattr(p, attribute.tag, description)
Dion Haefner's avatar
Dion Haefner committed
80 81 82 83 84 85 86 87 88 89 90
                else:
                    warn("Unrecognized attribute {0} for {1}.{2}".format(attribute.tag,category,key),XMLWarning)

            if not p in category_parameters:
                category_parameters.append(p)
            else:
                warn("{0}.{1} is defined multiple times".format(category,key),XMLWarning)

        xml_parameters[category] = category_parameters

    return xml_parameters