282 lines
9.9 KiB
Python
282 lines
9.9 KiB
Python
# -*- 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 = ('<p>', '</p>', ' ')
|
||
for s in symbol:
|
||
text = re.sub(s, '', text, flags=re.M|re.I|re.S)
|
||
# 替换为换行
|
||
text = re.sub(r'<.+[/]{1}>|<[/]{1}.>|<br>', r'\n', text, flags=re.M|re.I|re.S)
|
||
return text.strip()
|
||
|
||
def write_excel(self, file_name):
|
||
'''
|
||
将构造的字典树写入Excel文件中
|
||
'''
|
||
workbook = xlwt.Workbook(encoding='utf-8')
|
||
size = 100
|
||
# 标题
|
||
titles = (('模块', 35), ('用例标题', 50), ('重要性', 25), ('执行方式', 27), ('摘要', 80), ('前提', 80), ('步骤', 160), ('结果', 160))
|
||
result = {}
|
||
result['module'] = 0
|
||
result['case'] = 0
|
||
for sheet in self.__xml_tree:
|
||
sheet_name = sheet.get('sheet_name')
|
||
# 插入sheet名称
|
||
worksheet = workbook.add_sheet(sheet_name)
|
||
col = 0
|
||
row = 1
|
||
end = 0
|
||
title_row = 1
|
||
title_end = 0
|
||
# 写入标题
|
||
for t, w in titles:
|
||
width = w * size
|
||
worksheet.write(0, col, t, self.set_style(11))
|
||
worksheet.col(col).width = width
|
||
col = col + 1
|
||
# 写模块
|
||
for module in sheet.get(sheet_name):
|
||
# 写模块名
|
||
end = row + int(module.get('row')) - 1
|
||
worksheet.write_merge(row, end, 0, 0, module.get('module'), self.set_style(12))
|
||
row = end + 1 # 更新模块列
|
||
center = self.set_style()
|
||
left = self.set_style(align='left')
|
||
# 写用例
|
||
for case in module.get('testcase'):
|
||
title_end = int(case.get('row')) + title_row - 1
|
||
worksheet.write_merge(title_row, title_end, 1, 1, case.get('casename'), center)
|
||
worksheet.write_merge(title_row, title_end, 2, 2, case.get('importance'), center)
|
||
worksheet.write_merge(title_row, title_end, 3, 3, case.get('execution_type'), center)
|
||
summary = case.get('summary')
|
||
worksheet.write_merge(title_row, title_end, 4, 4, self.__auto_break(summary), left)
|
||
prec = case.get('preconditions')
|
||
worksheet.write_merge(title_row, title_end, 5, 5, self.__auto_break(prec), left)
|
||
# 步骤
|
||
step_row = title_row
|
||
for step in case.get('steps'):
|
||
actions = step.get('actions')
|
||
worksheet.write(step_row, 6, self.__auto_break(actions), left)
|
||
results = step.get('expectedresults')
|
||
worksheet.write(step_row, 7, self.__auto_break(results), left)
|
||
step_row = step_row + 1
|
||
title_row = title_end + 1
|
||
# 用例数+1
|
||
result['case'] = result['case'] + 1
|
||
|
||
# 模块数+1
|
||
result['module'] = result['module'] + 1
|
||
# 写入Excel
|
||
workbook.save(file_name)
|
||
return result
|
||
|
||
|
||
|
||
if __name__ == "__main__":
|
||
file = [os.path.join(os.getcwd(), 'test.xml')]
|
||
excel = os.path.join(os.getcwd(), 'test.xls')
|
||
dom = XmlToExcel()
|
||
dom.read_xml(file)
|
||
dom.write_excel(excel) |