# -*- coding:utf-8 -*- # 日期:2019年9月9日 # 作者:Wang WenJie # 版本:1.2.1 # 说明:用于TestLink导出后的Xml文件转成Excel文件 import xlwt from xml.dom.minidom import parse, Node import os import re import json class XmlToExcel(object): ''' TestLink导出的xml文件转Excel 构造字典树读取xml文件 ''' def __init__(self): # 全局字典树 self.__xml_tree = [] def __getText(self, node): ''' 获取节点的文本内容 Args: node: 节点 Returns: 节点中的文本 ''' if node is None: return '' if node.nodeType in [Node.TEXT_NODE, Node.CDATA_SECTION_NODE]: # return node.nodeValue return node.wholeText else: return '' def __get_importance(self, num): ''' 重要性序号转换成对应的中文 ''' if num == '1': return '低' elif num == '2': return '中' elif num == '3': return '高' return num def __get_exec_type(self, num): ''' 执行方式序号转换成对应的中文 ''' if num == '1': return '手工' elif num == '2': return '自动的' return num def __read_cases(self, case): ''' 读单个testcase节点,并返回字典 ''' case_dic = {} # 节点名称,即对应的标题 case_dic['casename'] = case.getAttribute('name') case_row = 0 for child in case.childNodes: # 如果遇到换行会读出TEXT_NODE,所以加上判断 if child.nodeType == Node.ELEMENT_NODE: # 摘要和前提 if child.tagName in ['summary', 'preconditions']: case_dic[child.tagName] = self.__getText(child.firstChild) elif child.tagName == 'importance': # 重要性 num = self.__getText(child.firstChild) case_dic[child.tagName] = self.__get_importance(num) elif child.tagName == 'execution_type': # 执行方式 num = self.__getText(child.firstChild) case_dic[child.tagName] = self.__get_exec_type(num) elif child.tagName == 'steps': # 步骤 case_dic['steps'] = [] for steps in child.getElementsByTagName('step'): step_dic = {} case_row = case_row + 1 for step in steps.childNodes: if step.nodeType == Node.ELEMENT_NODE: if step.tagName in ['actions', 'expectedresults']: step_dic[step.tagName] = self.__getText(step.firstChild) case_dic['steps'].append(step_dic) # 记录有多少步 case_dic['row'] = case_row return case_dic def __read_suites(self, root): ''' 读模块下的testsuite ''' suites = [] for testsuite in root.getElementsByTagName('testsuite'): module_tree = {} # 模块名 module = testsuite.getAttribute('name') module_tree['module'] = module module_tree['testcase'] = [] module_row = 0 for case in testsuite.getElementsByTagName('testcase'): case_dic = self.__read_cases(case) module_row = module_row + case_dic['row'] module_tree['testcase'].append(case_dic) # 记录模块占多少行 module_tree['row'] = module_row suites.append(module_tree) return suites def __read_single(self, root): ''' 读单节点用例 ''' suites = [] module_tree = {} module_tree['module'] = '' module_tree['testcase'] = [] module_row = 0 testcase = root.getElementsByTagName('testcase') for case in testcase: case_dic = self.__read_cases(case) module_row = module_row + case_dic['row'] # 记录模块占多少行 module_tree['row'] = module_row suites.append(module_tree) return suites def read_xml(self, xml_files): ''' 读xml文件主要方法 Args: xml_files: xml文件路径 ''' # 统计 result = {} result['success'] = 0 result['fail'] = 0 for file in xml_files: xml_dic = {} try: dom = parse(file) except: print('ERROR: 载入文件失败[{}]'.format(file)) result['fail'] = result['fail'] + 1 continue # 选择根节点 root = dom.documentElement if root.nodeName == 'testsuite': # 多用例集 suites = self.__read_suites(root) # 一级模块名,即sheet页名 sheet_name = root.getAttribute('name') if sheet_name.strip() == '': raise ValueError("xml文件有误, 请检查testsuite的name属性, 不能为空."); elif root.nodeName == 'testcases': # 单个用例 suites = self.__read_single(root) sheet_name = 'single' else: print('ERROR: 文件不是TestLink标准格式') result['fail'] = result['fail'] + 1 continue xml_dic[sheet_name] = suites xml_dic['sheet_name'] = sheet_name self.__xml_tree.append(xml_dic) result['success'] = result['success'] + 1 return result def set_style(self, height = 12, align = 'center'): ''' 设置写入单元格样式,包括文字大小,对齐方式 ''' # 字体样式 font = xlwt.Font() font.height = height * 20 font.name = '宋体' # 对齐方式 alignment = xlwt.Alignment() # 居中 if align == 'center': alignment.horz = xlwt.Alignment.HORZ_CENTER elif align == 'left': # 左对齐 alignment.horz = xlwt.Alignment.HORZ_LEFT alignment.vert = xlwt.Alignment.VERT_CENTER alignment.wrap = 1 # 自动换行 style = xlwt.XFStyle() style.alignment = alignment style.font = font return style def __auto_break(self, text): ''' 将html标记清除,并替换成对应的换行符 ''' symbol = ('
', '
', ' ') for s in symbol: text = re.sub(s, '', text, flags=re.M|re.I|re.S) # 替换为换行 text = re.sub(r'<.+[/]{1}>|<[/]{1}.>|