from lxml import etree import logging DEFAULT_NAMESPACE_KEY = 'ns' DEFAULT_NAMESPACE = {DEFAULT_NAMESPACE_KEY:'http://autosar.org/schema/r4.0'} class Arxml: def __init__(self, arxml_file_name: str) -> None: self.__file_name: str = arxml_file_name self.__root: etree.Element = self.get_arxml_root() @property def root(self) -> etree.Element: return self.__root def get_arxml_root(self): parser = etree.XMLParser(remove_blank_text=True) tree = etree.parse(self.__file_name, parser=parser) root = tree.getroot() return root ''' XPath 通过前缀 ns:'xxxxx' 进行namespace解析 find findall方法则是通过 {xxxxx}TAG-NAME 进行解析 ETXpath 类似find findall方法的形式,通过{xxxx}TAG-NAME ''' @staticmethod def get_arxml_namespace(element: etree.Element): ns = element.nsmap # add default namespace if None in ns: ns[DEFAULT_NAMESPACE_KEY] = ns[None] ns.pop(None) elif len(ns) == 0: ns = None return ns @staticmethod def get_formated_xpath_with_namespace_key(xpath_str: str, namespace_key: str = DEFAULT_NAMESPACE_KEY): ''' :param xpath_str: src xpath string :param namespace_key: need to :return: ''' namespace_prefix = '{}:'.format(namespace_key) if '' != namespace_key else '' result = xpath_str.replace('//', '**{}'.format(namespace_prefix)) result = result.replace('/', '/{}'.format(namespace_prefix)) result = result.replace('**', '//') return result @staticmethod def get_format_xpath_pattern(xpath_str, xpath_text='', xpath_rule=None, namespace_key=DEFAULT_NAMESPACE_KEY): ''' :param xpath_str: :param xpath_text: :param xpath_rule: CONTAINS TEXT_EQ ATTR_EQ :param namespace_key: :return: ''' xpath_with_ns = Arxml.get_formated_xpath_with_namespace_key(xpath_str, namespace_key) if xpath_rule == 'CONTAINS': xpath_suffix = '[contains(text(),"{}")]'.format(xpath_text) elif xpath_rule == 'TEXT_EQ': xpath_suffix = '[text()="{}"]'.format(xpath_text) elif (xpath_rule == 'ATTR_EQ' and isinstance(xpath_text, dict)): attr_name, attr_value = xpath_text.popitem() xpath_suffix = '[@{}={}]'.format(attr_name, attr_value) else: xpath_suffix = '' pass return xpath_with_ns + xpath_suffix @staticmethod def get_xpath_result(element, xpath_str, xpath_text='', xpath_rule=None): ns = Arxml.get_arxml_namespace(element) if ns is None: ns_key = '' else: ns_key = DEFAULT_NAMESPACE_KEY format_xpath = Arxml.get_format_xpath_pattern(xpath_str, xpath_text, xpath_rule, ns_key) # print(format_xpath) result = element.xpath(format_xpath, namespaces=ns) if len(result) == 0: result = None return result @staticmethod def get_all_match_element(root_element:etree.Element, xpath_str, xpath_text='', xpath_rule=None): result = Arxml.get_xpath_result(root_element, xpath_str, xpath_text, xpath_rule) return result @staticmethod def get_first_match_element(root_element:etree.Element, xpath_str, xpath_text='', xpath_rule=None): result = Arxml.get_all_match_element(root_element, xpath_str, xpath_text, xpath_rule) if result is not None: result = result[0] return result @staticmethod def get_brother_element(current_element:etree.Element, brother_tag, xpath_text='', xpath_rule=None): parent = current_element.getparent() if parent is not None: brother = Arxml.get_first_match_element(parent, brother_tag, xpath_text, xpath_rule) else: brother = None return brother @staticmethod def get_parent_element(current_element): return current_element.getparent() @staticmethod def get_container_text(current_element): if etree.iselement(current_element): return current_element.text else: return '' @staticmethod def xml_write_to_file(element, output_fileName): print(output_fileName) tree = etree.ElementTree(element) tree.write(output_fileName, pretty_print=True, xml_declaration=True, encoding='utf-8') logging.debug('Generate arxml file {}'.format(output_fileName)) @staticmethod def creat_child_new_element(element, element_tag, text_str='', attribute_dict={}): new_element = etree.Element(element_tag, attribute_dict) if text_str != '': new_element.text = text_str element.append(new_element) return new_element @staticmethod def creat_brother_new_element(cur_element, element_tag, text_str='', attribute_dict={}): par_element = cur_element.getparent() if par_element is not None: bro_element = Arxml.creat_child_new_element(par_element, element_tag, text_str, attribute_dict) else: bro_element = None return bro_element @staticmethod def get_split_end_value(long_str_value): return long_str_value.split('/')[-1] @staticmethod def get_element_tag(element): tag_with_ns = element.tag if tag_with_ns != '': if '}' in tag_with_ns: position = tag_with_ns.find('}') tag = tag_with_ns[position+1:] else: tag = tag_with_ns else: tag = '' return tag if __name__ == '__main__': arxml = Arxml('EH32_GW04_IpduM_ecuc.arxml') element = Arxml.get_first_match_element(arxml.root, './/DEFINITION-REF', 'IpduMRxDirectComInvocation', 'CONTAINS') par_ele = Arxml.get_parent_element(element) Arxml.creat_child_new_element(par_ele, 'aaaa', 'texttexttext', {'class':'1234'}) Arxml.creat_child_new_element(par_ele, 'bbbb', '', {'class': '1234'}) Arxml.creat_child_new_element(par_ele, 'bbbb1', 'dasfadfsad') cccc = Arxml.creat_child_new_element(par_ele, 'cccc') dddd = Arxml.creat_brother_new_element(cccc, 'dddd') Arxml.xml_write_to_file(arxml.root, 'test.arxml')