0%

用python将思维导图转换成树形列表

一直以来都喜欢用思维导图的方式去写用例,或者记录一些要做的任务。逻辑清晰,分工明确,提高我们的工作效率。但如果任务细化到一定程度,思维导图的展示会难看,放大了看不清逻辑关系,缩小了又看不清具体描述。自己python脚本,及reactjs前端技术,写了这个转换方法。

先简单说下我的工作步骤:
1.Xmind,编写用例,导出为html文件。
2.上传到后台服务端放导指定位置。
3.前台发起请求后台处理上传的文件并格式化返回,前台展示数据。

我一般都是写的逻辑向右的导图,首先我们把xmind的用例导出为html,导出页面上不要勾选任何选项。例如我的导出文件为test.html。
虽然导出的已经html了,但毫无格式可言,看起来是很吃力的。

通过脚本提取其中有用数据,并给它们每条一个id编号。

1
2
3
4
5
6
7
8
file = open('app/static/uploads/test1.html').read()
soup = BeautifulSoup(file)
allData = []
count = 1
for k in soup.find_all('a'):
value = k.text.replace(u'\xa0', u'$')
allData.append([count, value])
count += 1

这里看到‘replace(u’\xa0’, u’$’)’需要说明下,导出的数据他们的父子关系主要是靠空格来区分,这里\xa0就是空格,方便后面数据转换,我把它们替换成了’$’,所以可以说,我们的导图文本里不能写这个关键字,不然会有错误。

下面就是给它们理清楚出父子关系了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
sz = []
allData[0].append(0)
allData[1].append(0)
sz.append(allData[0])
sz.append(allData[1])
for i in range(len(allData)):
if i > 1:
prew_index = len(allData[i - 1][1]) - len(allData[i - 1][1].replace('$', ''))
now_index = len(allData[i][1]) - len(allData[i][1].replace('$', ''))
if now_index - prew_index == 1:
allData[i].append(allData[i - 1][0])
elif now_index - prew_index == 0:
try:
allData[i].append(allData[i - 1][2])
except:
print allData[i - 1]
elif now_index - prew_index < 0:
for l in range(0, len(sz)):
# 找新数组
_prew_index = len(sz[(len(sz) - 1) - l][1]) - len(sz[(len(sz) - 1) - l][1].replace('$', ''))
if now_index - _prew_index == 0:
allData[i].append(sz[(len(sz) - 1) - l][2])
break
sz.append(allData[i])

获取到的sz数组,就是当前导出的数据格式化数据了,每条数据都有个自己的id,名字,父id。但我的reactjs前端页面需要的是,有子集的树形结构数据。

通过下面的遍历方法把数据再次格式化处理:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
def getchild(pid):
result = []
for obj in sz:
if obj[2] == pid:
result.append({
"id": obj[0],
"title": obj[1].replace('$',''),
"pid": obj[2],
"children": getchild(obj[0]),
})

return result

newResult = getchild(0)
for item in range(1, len(newResult)):
newResult[0]["children"].append(newResult[item])
for item in range(1,len(newResult)):
newResult.pop()

到这里,数据处理的核心部分已经完成了。但要给前端页面展示,我还要把脚本封装到服务端,并通过接口传给前端页面。
我用的flask,提供restful接口。
前端部分用的是react框架,主要是用antd的ui库:
核心部分如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
class CaseList extends React.Component{
state = {
fetch_data:[],
...

}
fetchList=()=>{
var par = "entry=0"
fetch('http://192.168.1.101:5000/gettasklist',{
method: "POST",
mode: "cors",
headers: {
"Content-Type": "application/x-www-form-urlencoded"
},
body: par
})...
}
render(){
const { fetch_data} = this.state;
const columns = [ {
title: 'title',
dataIndex: 'title',
key: 'title',
render: text => <a style={{marginLeft:30,fontSize:16}}>{text}</a>,
}];
return(
<Page title="case列表" loading={this.state.isLoading}>
<Table rowKey="id" columns={columns} dataSource={fetch_data} indentSize={50}/>
</Page>
);
}
}

实际使用时,我是通过一个上传页面直接上传导出文件到服务器的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<Page title="上传导出文件" loading={this.state.isLoading}>
<div style={{alignItems:'center', justifyContent:"center",display:'flex',flex:1, flexDirection:'column',
marginTop:"20%"}}>
<Upload {...props}>
<Button>
<Icon type="upload" /> Select File
</Button>
</Upload>
<Button
className="upload-demo-start"
type="primary"
onClick={this.handleUpload}
disabled={this.state.fileList.length === 0}
loading={uploading}
style={{marginTop:20}}
>
{uploading ? 'Uploading' : 'Start Upload' }
</Button>
</div>
</Page>

后续还将优化前端和脚本生成的数据,通过写入数据库,前端可以执行测试通过、已完成等,以记录我们的测试点的执行状态。前端部分感兴趣的可以看下我的源码:https://github.com/t880216t/manager-web