Passed
Pull Request — master (#69)
by
unknown
01:06
created

SimpleXml.build_propfind_datas()   B

Complexity

Conditions 6

Size

Total Lines 31
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 18
dl 0
loc 31
rs 8.5666
c 0
b 0
f 0
cc 6
nop 4
1
# -*- coding: utf-8 -*-
2
"""
3
XML builder/parser
4
"""
5
import xml.etree.ElementTree as ET
6
from nextcloud.compat import encode_string
7
from nextcloud.common.properties import NAMESPACES_MAP
8
9
10
def _prepare_xml_parsing(string):
11
    return encode_string(string)
12
13
def _safe_xml_val(val):
14
    if isinstance(val, int):
15
        val = str(val)
16
    return val
17
18
class SimpleXml:
19
    """
20
    Static class to build and parse XML datas
21
    """
22
    namespaces_map = NAMESPACES_MAP
23
    supported_field_types = list(NAMESPACES_MAP.keys())
24
    xml_namespaces_map = {'xmlns:' + k: v for k, v in NAMESPACES_MAP.items()}
25
26
    @classmethod
27
    def _to_fields_list(cls, fields_hash):
28
        props_xml = []
29
        for field_type in fields_hash:
30
            if field_type not in cls.supported_field_types:
31
                pass
32
            else:
33
                for field in fields_hash[field_type]:
34
                    props_xml.append('{}:{}'.format(field_type, field))
35
36
        return props_xml
37
38
    @classmethod
39
    def _to_field_vals_list(cls, fields_hash):
40
        props_xml = {}
41
        for field_type in fields_hash:
42
            if field_type not in cls.supported_field_types:
43
                pass
44
            else:
45
                vals = fields_hash[field_type]
46
                for field in vals:
47
                    props_xml['{}:{}'.format(field_type, field)] = _safe_xml_val(vals[field])
48
49
        return props_xml
50
51
    @classmethod
52
    def _tostring(cls, root):
53
        return ET.tostring(root)
54
55
    @classmethod
56
    def fromstring(cls, data):
57
        """
58
        Fetch xml.etree.ElementTree for input data
59
60
        :param data:   raw xml data
61
        :returns:      :class:xml.etree.ElementTree
62
        """
63
        return ET.fromstring(_prepare_xml_parsing(data))
64
65
    @classmethod
66
    def build_propfind_datas(cls, instr=None, filter_rules=None, fields=None):
67
        """
68
        Build XML datas for a PROPFIND querry.
69
70
        :param instr:        http instruction (default: PROPFIND)
71
        :param filter_rules: a dict containing filter rules separated by
72
                             namespace. e.g. {'oc': {'favorite': 1}}
73
        :param fields:       a dict containing fields separated by namespace
74
                             e.g. {'oc': ['id']}
75
        :returns:            xml data (string)
76
        """
77
        if not instr:
78
            instr = 'd:propfind'
79
80
        root = ET.Element(instr, cls.xml_namespaces_map)
81
        props = cls._to_fields_list(fields or {})
82
        if props:
83
            prop_group = ET.SubElement(root, 'd:prop')
84
            for prop in props:
85
                ET.SubElement(prop_group, prop)
86
87
        rules = cls._to_field_vals_list(filter_rules or {})
88
        if rules:
89
            rule_group = ET.SubElement(root, 'oc:filter-rules')
90
            for k in rules:
91
                rule = ET.SubElement(rule_group, k)
92
                val = rules[k]
93
                rule.text = _safe_xml_val(val)
94
95
        return cls._tostring(root)
96
97
    @classmethod
98
    def build_propupdate_datas(cls, values):
99
        """
100
        Build XML datas for a PROPUPDATE querry.
101
102
        :param values:       a dict containing values separated by namespace
103
                             e.g. {'oc': {'favorite': 1}}
104
        :returns:            xml data (string)
105
        """
106
        root = ET.Element('d:propertyupdate', cls.xml_namespaces_map)
107
        vals = cls._to_field_vals_list(values)
108
        if vals:
109
            set_group = ET.SubElement(root, 'd:set')
110
            val_group = ET.SubElement(set_group, 'd:prop')
111
            for k in vals:
112
                val = ET.SubElement(val_group, k)
113
                val.text = vals[k]
114
115
        return cls._tostring(root)
116