python xmind to Excel (puppet Lolo original)

Requirements: Convert the xmind file to an Excel file, and add UI interface operations to reduce the difficulty of operation.

This requirement can be made clear in one sentence, but in fact there is still a lot of work to be done:

1. Understand the Xmind file structure

2. Extract the branch content of the Xmind file (emphasis)

3. UI interface (non-essential)

First, understand the Xmind file structure

1. xmind file format: tree branch structure (you can first think about how to extract the content of each branch).

 

 

 

What is the form of Excel extraction: the trunk is connected with the branch, and the "\" sign is used to connect. (After understanding the principle, it can also be written in other forms you want)

Example:

https\Tunnel to meaning\Tunnel (tunnel), intermediate entity

https\Tunnel to meaning\hidden: rules - hidden connections

 

Second, extract the branch content of the Xmind file (emphasis)

So how to parse the above as a specific data structure? Use "from xmindparser import xmind_to_dict", and use the xmindparser package to convert it into a dictionary format for processing.

Another example:

 

 

What can this xmind file be converted to through xmind_to_dict?

  {'title': 'A', 'topics': [{'title': 'B1'}, {'title': 'B2', 'topics': [{'title': 'C1'}, {'title': 'C2'}]}, {'title': 'B3'}]}

Still not intuitive enough, let’s expand it with a json analyzer:

[
  {
'title': 'Canvas 1',
    'topic': {
      'title': 'A',
      'topics': [
        {
          'title': 'B1'
        },
        {
          'title': 'B2',
          'topics': [
            {
              'title': 'C1'
            },
            {
              'title': 'C2'
            }
          ]
        },
        {
          'title': 'B3'
        }
      ]
    },
    'structure': 'org.xmind.ui.map.unbalanced'
  }
]

 

The content is installed in a list, the outermost title of the dictionary is "canvas 1", and the topic is loaded with the content we need (it can be seen that other locations are called topics), which is not in the xmind file. It has been verified that this is a fixed value. can be omitted. Then by taking the list, A is the value in the dictionary, the key is the title, and its child nodes are installed in the topics branch. After processing, the outermost layer is dict:

 

So the question is, how to process it into the desired form? Do you take key and value layer by layer?

Of course not, the workload will be very huge, and it is not conducive to reading and modification. Do you remember what you thought about just now? Here we need to use what you think, yes, recursion.

Why use recursion, let's take a closer look at the structure:

The three child nodes of A are B1, B2, B3, and the child node of B2 is C1C2. See the picture above, what do you think of?

1. The title and child nodes are placed in different item s, that is, the topic is placed in the root node, and the topic is placed in its child nodes.

2. What about topics without child nodes? A point like C1C2 has no child nodes, and we found that it has no topics; at the same time, there are no child nodes to prove that it is the last layer of this branch; imagine, if A has no child nodes, it is the only one? As you can imagine, it only has a title and no topics.

3. The child node of A is a list, and the list can have multiple child nodes. If the child node has child nodes, it will have topics, and if not, there will be no topics.

4. The title is always loaded with a string, while the topics can be loaded with a list, with a dict in the list, or without topics.

After watching four o'clock, you still feel very chaotic?

  We need to take the child nodes layer by layer to get the A\B2\C1, A\B2\C2 we want. The node value is always in the title, while the child node is in the dict in the dict and list, and the child node is in the dict. Some of them only have a title, and some have a title and a topics. As mentioned above, those with topics have their child nodes.

So it should be clearer now, right? Still not clear? The pseudocode is again:

If Input dictionary:

When the dictionary only has a title:

Operation 1

When the dictionary has title and topics:

Operation 2

If Enter list:

Traverse the dictionary in list:

Perform operations on each dictionary 3

If the input is neither a dictionary nor a list:

     output value

 

 

The thinking framework has been built, so what are operations 1, 2, and 3? In fact, it is the repeated operation of this framework, you can just call it yourself, not strictly speaking, this is the popular explanation of recursion.

Let's paste the code:

 1 def TraversalXmind(root,rootstring):
 2     if isinstance(root, dict):
 3         if len(root) == 2:
 4             TraversalXmind(root['topics'], str(rootstring) )
 5         if len(root) == 1:
 6             TraversalXmind(root['title'],str(rootstring)  )
 7 
 8     elif isinstance(root, list):
 9         for sonroot in root:
10             TraversalXmind(sonroot, str(rootstring)  + "\\" + sonroot['title'])
11 
12     elif isinstance(root,str):
13         print(str(rootstring) )
14 
15 # TraversalXmind(root, "\\AA")

What is the complete code?

Uninstall the above conversion process in model.py:

 1 # -*-coding:utf-8 -*-
 2 # Author  : zhengyong
 3 # Time    : 2020/11/5 23:06
 4 # FileName: model.py
 5 
 6 from xmindparser import xmind_to_dict
 7 import os,csv
 8 # filepath1 = os.path.abspath(os.path.dirname(__file__))
 9 # print(filepath1)
10 
11 # filepath = "D:\\test.xmind"
12 # inputedXmind = xmind_to_dict(filepath)
13 # root = inputedXmind[0]['topic']
14 
15 def traversalXmind(root, rootstring,lisitcontainer):
16     """
17     Function: recursive dictionary file gets easy to write Excel form format.
18     Notice: rootstring use both str to handle Chinese characters
19     @param root: Will xmind processed dictionary document
20     @param rootstring: xmind root header
21     """
22     if isinstance(root, dict):
23         if len(root) == 2:
24             traversalXmind(root['topics'], str(rootstring),lisitcontainer)
25         if len(root) == 1:
26             traversalXmind(root['title'], str(rootstring),lisitcontainer)
27 
28     elif isinstance(root, list):
29         for sonroot in root:
30             traversalXmind(sonroot, str(rootstring) + "\\" + sonroot['title'],lisitcontainer)
31 
32     elif isinstance(root, str):
33          lisitcontainer.append(str(rootstring))
34 
35 def getCase(root):
36     rootstring = root['title']
37     lisitcontainer = []
38     traversalXmind(root, rootstring,lisitcontainer)
39     # print(lisitcontainer)
40     return lisitcontainer
41 
42 # def getTestCase(filename,lisitcontainer,directory,group,runType,testcaseType,testType):
43 #     header = [
44 #         'test case path',
45 #         'test case name',
46 #         'Test case description',
47 #         'Plan execution time (minutes)',
48 #         'Step description',
49 #         'expected outcome',
50 #         'priority',
51 #         'group',
52 #         'execution way',
53 #         'test module',
54 #         'version number',
55 #         'use case type',
56 #         'test type',
57 #         'Associated Story Cards ID',
58 #     ]
59 #
60 #     with open(filename,'w',newline='') as f:
61 #         writer = csv.DictWriter(f,fieldnames=header),
62 #         writer.writeheader()
63 #         for row in lisitcontainer:
64 #             writer.writerow({
65 #                 'test case path': directory,
66 #                 'test case name': row,
67 #                 'group': group,
68 #                 'execution way': runType,
69 #                 'use case type':testcaseType,
70 #                 'test type': testType,
71 #             })

 

Third, the UI interface

The UI interface is written in tkinter, directly on the code:

  1 #-*-coding:utf-8 -*-
  2 # Author  : zhengyong
  3 # Time    : 2020/11/14 23:54
  4 # FileName: main1.py
  5 # https://github.com/ndnmonkey/transXmindToCSV.git
  6 
  7 import model
  8 from xmindparser import xmind_to_dict
  9 import tkinter
 10 from tkinter import filedialog
 11 from tkinter import *
 12 import os,csv
 13 
 14 
 15 window = tkinter.Tk()
 16 window.title("Use case export tool")
 17 # Settings window icon
 18 # window.iconbitmap("D:\Code\Python\XmindToExcel\image\icon.ico")
 19 # window.iconbitmap("image\ifavicon.ico")
 20 window.geometry("400x370+200+50")
 21 
 22 # title
 23 labeltitle = tkinter.Label(window,text = "Use case export tool",font = ('Young round',20)).pack()
 24 
 25 # Create a menu bar
 26 MenuBar = tkinter.Menu(window)
 27 # Put the menu bar in the main window
 28 window.config(menu=MenuBar)
 29 # Create file menu, do not show split window
 30 fileBar = tkinter.Menu(MenuBar, tearoff=0)
 31 # Add file menu item
 32 fileBar.add_command(label="Instructions for use")
 33 # fileBar.add_command(label="Contact the author")
 34 # Create dividing lines
 35 # fileBar.add_separator()
 36 fileBar.add_command(label="quit", command=window.destroy)
 37 # Add file menu to menu bar
 38 MenuBar.add_cascade(label="menu", menu=fileBar)
 39 
 40 xlabe = 20
 41 xtext = 80
 42 y =10
 43 step = 30
 44 textwidth = 250
 45 
 46 inputtext1 = tkinter.StringVar(value='\General version use case\current version name\Name\Requirement name')
 47 labe1 = tkinter.Label(window, text='use case path:').place(x=xlabe,y = y + step)
 48 text1 = tkinter.Entry(window, show=None, textvariable=inputtext1)
 49 text1.place(width=textwidth,x=xtext+ 1*step,y=y + step)
 50 
 51 inputtext2 = tkinter.StringVar(value='Team leader name')
 52 labe2 = tkinter.Label(window, text='Team leader name:').place(x=xlabe,y=y + 2*step)
 53 text2 = tkinter.Entry(window, show=None, textvariable=inputtext2)
 54 text2.place(width=textwidth,x=xtext+ 1*step,y=y + 2*step)
 55 
 56 inputtext3 = tkinter.StringVar(value='manual testing')
 57 labe3 = tkinter.Label(window, text='execution way:').place(x=xlabe,y=y + 3*step)
 58 text3 = tkinter.Entry(window, show=None, textvariable=inputtext3)
 59 text3.place(width=textwidth,x=xtext+ 1*step,y=y + 3*step)
 60 
 61 inputtext4 = tkinter.StringVar(value='System use case')
 62 labe4 = tkinter.Label(window, text='use case type:').place(x=xlabe,y=y + 4*step)
 63 text4 = tkinter.Entry(window, show=None, textvariable=inputtext4)
 64 text4.place(width=textwidth,x=xtext+ 1*step,y=y + 4*step)
 65 
 66 inputtext5 = tkinter.StringVar(value='manual testing')
 67 labe5 = tkinter.Label(window, text='test type:').place(x=xlabe,y=y + 5*step)
 68 text5 = tkinter.Entry(window, show=None, textvariable=inputtext5)
 69 text5.place(width=textwidth,x=xtext+ 1*step,y=y + 5*step)
 70 
 71 def getTextValues():
 72     templist = []
 73     var1 = text1.get();templist.append(var1)
 74     var2 = text2.get();templist.append(var2)
 75     var3 = text3.get();templist.append(var3)
 76     var4 = text4.get();templist.append(var4)
 77     var5 = text5.get();templist.append(var5)
 78     # print("1",templist)
 79     return templist
 80 
 81 casebutton1 = tkinter.Button(window,text = '1,Submit use case information',width=5,height=1,command=getTextValues)
 82 casebutton1.place(x=110,y=y + 6*step)
 83 casebutton1.configure(width = 34, height = 2)
 84 
 85 def open_file():
 86     templist = getTextValues()
 87     # print("2",templist)
 88     filename = filedialog.askopenfilename(title='Open Xmind document', filetypes=[('xmind', '*.xmind')])
 89 
 90     entry_filename.delete(0, END)
 91     entry_filename.insert('insert', filename)
 92     # print(entry_filename,type(entry_filename))
 93 
 94     # print(filename)
 95     fname = entry_filename.get()  #use get extract entry content in
 96     fname = str(fname).replace('/','\\\\')
 97     # print("fname",fname)
 98 
 99     # filepath = "D:\\test.xmind"
100     # inputedXmind = xmind_to_dict(filepath)
101     # root = inputedXmind[0]['topic']
102     #
103     inputedXmind = xmind_to_dict(fname)
104     root = inputedXmind[0]['topic']
105     lisitcontainer = model.getCase(root)
106     # print(lisitcontainer)
107 
108     # templist
109     directory = templist[0]
110     group = templist[1]
111     runType = templist[2]
112     testcaseType = templist[3]
113     testType = templist[4]
114     # filename = 'testcase.csv'
115     header = [
116         'test case path',
117         'test case name',
118         'Test case description',
119         'Plan execution time (minutes)',
120         'Step description',
121         'expected outcome',
122         'priority',
123         'group',
124         'execution way',
125         'test module',
126         'version number',
127         'use case type',
128         'test type',
129         'Associated Story Cards ID',
130     ]
131     # print(filename)  #D:\\test.xmind
132     savepath = fname.split('.')[0] + ".csv"
133     # print("savepath:",savepath)
134 
135     with open(savepath, 'w', newline='') as f:
136         writer = csv.DictWriter(f, fieldnames=header)
137         writer.writeheader()
138         for row in lisitcontainer:
139             writer.writerow({
140                 'test case path': directory,
141                 'test case name': row,
142                 'group': group,
143                 'execution way': runType,
144                 'use case type': testcaseType,
145                 'test type': testType,
146             })
147 
148 # set up button button accept function
149 importbutton = tkinter.Button(window, text="2,import Xmind document", command=open_file)
150 importbutton.place(x=110,y=y + 9*step)
151 importbutton.configure(width =34,height=2)
152 
153 # set up entry
154 entry_filename = tkinter.Entry(window, width=30, font=("Song Dynasty", 10, 'bold'))
155 entry_filename.place(width=textwidth,x=xtext+ 1*step,y=y + 8*step)
156 
157 # Copyright page
158 labelright = tkinter.Label(window,text = "version 0.3  bug repair: zhengyong731@pingan.com.cn",font = ('Song Dynasty',8)).place(x=60,y=350)
159 # Tk().iconbitmap('D:\Code\Python\XmindToExcel\image\icon.ico')
160 window.mainloop()

Then there is another question at this time, what is the result after running?

 

Use pyinstaller to package code files into executable files:

method:

1. Install pyinstaller (no specific introduction)

2. Use:

   Command Line:

pyinstaller -F main filename.py

What should I do if there is a black box when running the executable file?

pyinstaller -F -w mycode.py (-w is to cancel the window)

3. Where is the generated executable file?

In the same-level folder dist of the main file,

4. The specific file structure:

 

4. Statement

All the codes are original, because I can't find any available tutorials, and I know the difficulty of finding tutorials, so I'm throwing some ideas.

Welcome to reprint, please indicate the following:

My ID on cnblogs is puppet Lolo, and the blog address is https://www.cnblogs.com/two-peanuts/ All blogs containing original claims are my own original work. The contents of the blog are the results of my independent research, except for the cited references that have been indicated. Unless otherwise specified, use Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Mainland China License Agreement License.

Five, github address

The specific file structure has been uploaded to github, github address : https://github.com/ndnmonkey/transXmindToCSV, star is welcome.

 

Tags: Python

Posted by Goon on Sun, 08 May 2022 00:42:39 +0300