简介
xlxs文件内容如下:
包含四个字段,但最后一个字段用不到。
要求转化为形式如下的xml文件:
开发步骤
1.选定语言
这里使用了golang语言,常用语言的步骤一定是类似的
2.大致思考开发的主要过程:
经过思考应该包含以下几个部分:
1)解析源文件
2)在内存中进行调整,对层级关系进行调整,生成内存中的对象结构
3)转化为XML形式的字符串
4)新建并写入文件
3.下面对每一个步骤进行操作
解析源文件
考虑这不是一个简单的text文件,这是一个看似是二进制文件的xlxs文件,无法直接解析文件。考虑使用第三方的插件进行解析。
百度“golang xlxs解析”,随便找了一个 文章(点击查看) 。
使用第三方插件的步骤一般就是:1.引入包,2.根据例子了解主要功能的使用方法。
解析完毕的标志就是能够将主要的信息提取出来,使得可以使用程序进行处理。
内存调整
这时候,这个任务就可以看成一个算法题了,已经可以进行抽象处理了。
源数据包括areaID , areaName 和 parentID。
经过大体的查看,发现parentID为0的为省的ID,其ID格式为XX0000,地级市的ID格式为XXXX00,所以可根据这个规律将一行的数据解析为具体是省还是市或者区县。
相关函数如下:
func isProvince(id int) bool {
str := strconv.Itoa(id) // if strings.Compare("0000", str[2:]) == 0 {
return true } return false } func isCity(id int) bool {
str := strconv.Itoa(id) // if strings.Compare("0000", str[2:]) != 0 && strings.Compare("00", str[4:]) == 0 {
return true } return false }
下面考虑如何组织出最后的层级结构。
遍历数据表可以得到一组area的信息,包括id,name和parent。
考虑id是唯一的,所以,可以使用散列的方式进行存储,声明出一个(6个零,7位数)的数组,用对应id作为下标存在数组中。
这个对象的结构大概是这样,我们首先将省市县抽象为一种对象Area:
type Area struct {
areaId int areaName string areaParent int areaType int // 1-p 2-city 3-country areaList []Area }
算法步骤如下:
(1 获得area,遍历所有的xlsx的数据行,生成area对象按照ID存在area数组中。
(2 遍历area数组,处理所有的类型为区县的数据,遍历到的area为区县时,将之加到对应的市的areaList中,这里用ID做下标存的用处就来了,可以直接找到所属的市。
(3 再遍历一边area数组,处理所有的地级市,原理和方法与(2类似,将地级市添加到对应的省的areaList中。
理论上已完成了层级关系的处理。
考虑如何转化为xml字符串
type AreaList struct {
ProvinceList []Province `xml:"Province"` } type County struct {
ID int `xml:"areaId,attr"` Name string `xml:"areaName,attr"` ParentId int `xml:"-"` } type City struct {
ID int `xml:"areaId,attr"` Name string `xml:"areaName,attr"` ParentId int `xml:"-"` Areas []County `xml:"County"` } type Province struct {
ID int `xml:"areaId,attr"` Name string `xml:"areaName,attr"` Cites []City `xml:"City"` }
contentXML, err := xml.Marshal(areaList)
写到文件
最后一步,将上述字符串写到文件中:
继续百度!!随便找了一文章,点击查看 稍微有点坑,他给转化了两边,导致最后生成的文件内容多了一倍的内容。
「注」,哦对,最后生成的文件应该是没有格式化的,在数据传输的角度来看,这无伤大雅,文件可以使用,但是从看的角度和装X的角度的话,额。。。咱要不转化一下?
百度XML格式化工具:随便找一个,点击查看
这回好看咯!!
下面给出所有的源代码:
package main import ( "encoding/xml" "fmt" "github.com/tealeg/xlsx" "os" "strconv" "strings" ) type AreaList struct {
ProvinceList []Province `xml:"Province"` } type County struct {
ID int `xml:"areaId,attr"` Name string `xml:"areaName,attr"` ParentId int `xml:"-"` } type City struct {
ID int `xml:"areaId,attr"` Name string `xml:"areaName,attr"` ParentId int `xml:"-"` Areas []County `xml:"County"` } type Province struct {
ID int `xml:"areaId,attr"` Name string `xml:"areaName,attr"` Cites []City `xml:"City"` } func main() {
areaList := AreaList{
ProvinceList: ExcelParse2("area.xlsx"), } contentXML, err := xml.Marshal(areaList) if err != nil {
fmt.Println("err ", err) } else {
WriteWithFileWrite("out.xml", string(contentXML)) } } type Area struct {
areaId int `xml:"areaId"` areaName string `xml:"areaName"` areaParent int `xml:"-"` areaType int // 1-p 2-city 3-country areaList []Area } //xlsx文件解析 func ExcelParse2(fileName string) []Province {
filePath := "upload/" + fileName xlFile, err := xlsx.OpenFile(filePath) if err != nil {
} //开辟除表头外的行数的数组内存 provinceArr := make([]Province, 0) areaArr := make([]Area, ) //遍历sheet for _, sheet := range xlFile.Sheets {
//遍历每一行 for rowIndex, row := range sheet.Rows {
//跳过第一行表头信息 if rowIndex == 0 {
continue } //遍历每一个单元 id, _ := row.Cells[0].Int() name := row.Cells[1].String() parent, _ := row.Cells[2].Int() aarea := Area{
areaId: id, areaName: name, areaParent: parent, } if isProvince(id) {
aarea.areaType = 1 //areass = append(areass, p) } else if isCity(id) {
aarea.areaType = 2 //areass[id] = c //areass = append(areass, c) } else {
aarea.areaType = 3 //areass = append(areass, a) } areaArr[aarea.areaId] = aarea } } //第一遍扫描将所有的Country放在City类型里 for _, coun := range areaArr {
if coun.areaType == 3 {
areaArr[coun.areaParent].areaList = append(areaArr[coun.areaParent].areaList, coun) } } //第二遍扫描将所有的City放在Province类型中 for _, ci := range areaArr {
if ci.areaType == 2 {
areaArr[ci.areaParent].areaList = append(areaArr[ci.areaParent].areaList, ci) } } //生成返回数组 for _, p := range areaArr {
if p.areaType == 1 {
citys := make([]City, 0) for _, c := range p.areaList {
countrys := make([]County, 0) for _, a := range c.areaList {
countrys = append(countrys, County{
ID: a.areaId, Name: a.areaName, }) } citys = append(citys, City{
ID: c.areaId, Name: c.areaName, Areas: countrys, }) } provinceArr = append(provinceArr, Province{
ID: p.areaId, Name: p.areaName, Cites: citys}) } } return provinceArr } func isProvince(id int) bool {
str := strconv.Itoa(id) // if strings.Compare("0000", str[2:]) == 0 {
return true } return false } func isCity(id int) bool {
str := strconv.Itoa(id) // if strings.Compare("0000", str[2:]) != 0 && strings.Compare("00", str[4:]) == 0 {
return true } return false } // //func isArea(id int) bool {
// if !isProvince(id) && !isCity(id) {
// return true // } // return false //} func WriteWithFileWrite(name, content string) {
fileObj, err := os.OpenFile(name, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644) if err != nil {
fmt.Println("Failed to open the file", err.Error()) os.Exit(2) } defer fileObj.Close() if _, err := fileObj.WriteString(content); err == nil {
fmt.Println("Successful writing to the file with os.OpenFile and *File.WriteString method.", content) } }