go语言与excel的序列化与反序列化(1)

很多时候,尤其是游戏开发中,策划往往将文档,数据等写入excel中,程序,需要通过各种方式解析excel,让程序可以读。

常见的方案有:

1.将excel转换为csv,逗号分割方式,程序通过split逗号按照特定格式进行转换。(功能不够强大,格式要求很严,无法灵活配置很多特殊的功能)

2.将excel转换为lua table。这是C++游戏开发的常用方式。 (无法通过c++对象序列化为excel)

3.将excel转换到数据库的table中。类似方案2,不同的是,这里是转换到数据库的表中。 (无法通过c++对象序列化为excel)

4.将excel转换为xml格式,然后通过如,java中simple_xml等支持xml序列化和反序列化的框架,进行序列化和反许序列化。

5....



为什么要这样做。游戏开发中,首先要明确一点,当一个功能要开发的时候,首先不是策划配表,而是程序先按照大致的方案,创建对应的对象数据,有了对象,类型,将该类型进行序列化为.xml然后,策划按照该.xml格式添加配置,每当有新的功能要添加时,程序在原有的类型的基础上添加新的类型,读取原来的xml,通过新的类型,重新生成xml文件,然后,策划仅仅添加新增的属性,在这种情况下,程序的改动就非常少,关注的点,也仅仅在新增的属性上。


我们编写序列化的简单例子:

/**
 * Created by Administrator on 13-12-25.
 */
package main

import (
	"fmt"
	"os"
	"reflect"
	"encoding/xml"
)

var xmlHead []byte = []byte("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?><?mso-application progid=\"Excel.Sheet\"?>")

type Workbook struct {
	Xmlns         string `xml:"Xmlns,attr"`
	Xmlns_o       string `xml:"xmlns:o,attr"`
	Xmlns_x       string `xml:"xmlns:x,attr"`
	Xmlns_ss      string `xml:"xmlns:ss,attr"`
	Xmlns_html    string `xml:"xmlns:html,attr"`
	Xmlns_dt      string `xml:"xmlns:dt,attr"`

	Worksheets    []Worksheet `xml:"Worksheet"`
}

func newWorkbook() *Workbook {
	return &Workbook{
		Xmlns:"urn:schemas-microsoft-com:office:spreadsheet",
		Xmlns_o:"urn:schemas-microsoft-com:office:office",
		Xmlns_x:"urn:schemas-microsoft-com:office:excel",
		Xmlns_ss:"urn:schemas-microsoft-com:office:spreadsheet",
		Xmlns_html:"http://www.w3.org/TR/REC-html40",
		Xmlns_dt:"uuid:C2F41010-65B3-11d1-A29F-00AA00C14882"}
}

type Worksheet struct {
	Name  string `xml:"ss:Name,attr"`
	Table Table  `xml:"Table"`
}

type Table struct {
	ExpandedColumnCount int  `xml:"ss:ExpandedColumnCount,attr"` // 属性数量
	ExpandedRowCount    int  `xml:"ss:ExpandedRowCount,attr"`    // 数据条数
	FullColumns         int  `xml:"x:FullColumns,attr"`
	FullRows            int  `xml:"x:FullRows,attr"`
	DefaultColumnWidth  float32 `xml:"ss:DefaultColumnWidth,attr"`
	DefaultRowHeight    float32 `xml:"ss:DefaultRowHeight,attr"`
	Rows                []Row   `xml:"Row"`
}

func newTable(columnCount, rowCount int) *Table {
	return &Table{
		ExpandedColumnCount:columnCount,
		ExpandedRowCount:rowCount,
		FullColumns:1,
		FullRows:1,
		DefaultColumnWidth:60,
		DefaultRowHeight:16}
}

type Row struct {
	Cells []Cell `xml:"Cell"`
}

type Cell struct {
	Data Data `xml:"Data"`
}

type Data struct {
	Type  string      `xml:"ss:Type,attr"`
	Value interface{} `xml:",chardata"`
}

func newCell(_type string, _value interface{}) Cell {
	data := Data{Type: _type, Value: _value}
	cell := Cell{Data: data}

	return cell
}


func MarshalExcelXml(arr []interface {}) {

	var name string = "unknow"

	book := newWorkbook()
	sheet := Worksheet{}
	columnCount, rowCount := 0, len(arr)
	for _, v := range arr {
		if v != nil {
			t := reflect.TypeOf(v)
			name = t.Name()+"s"
			columnCount = t.NumField()
			break
		}
	}

	fmt.Fprintf(os.Stdout, "name %s columnCount %d, rowCount %d\n", name, columnCount, rowCount)

	if columnCount > 0 && rowCount > 0 {
		table := newTable(columnCount, rowCount)
		fmt.Fprintf(os.Stdout, "table %v\n", table)
		rows := make([]Row, rowCount)
		for index := 0; index < rowCount; index++ {
			fmt.Fprintf(os.Stdout, "index = %d v = %v\n", index, arr[index])
			if arr[index] != nil {
				val := reflect.ValueOf(arr[index])
				cells := make([]Cell, columnCount)
				for i := 0; i < columnCount; i++ {
					fieldValue := val.Field(i)
					fmt.Fprintf(os.Stdout, "fieldValue %v Type %v \n", fieldValue, fieldValue.Type())
					var cell Cell
					switch fieldValue.Kind() {
					case reflect.Int:
						cell = newCell("Number", fieldValue.Int())
					case reflect.String:
						cell = newCell("String", fieldValue.String())
					}
					cells[i] = cell
				}
				rows[index].Cells = cells
			}
		}
		table.Rows = rows
		sheet.Name = "tasks"
		sheet.Table = *table
		book.Worksheets = make([]Worksheet, 1)
		book.Worksheets[0] = sheet

		f, err := os.OpenFile("c:/"+name+".xml", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, os.ModeAppend)
		defer f.Close()

		if err != nil {
			fmt.Fprintf(os.Stderr, "error : %s", err.Error())
			return
		}

		n, err := f.Write(xmlHead)
		if err == nil && n < len(xmlHead) {
			fmt.Fprintf(os.Stderr, "error : write Fail")
			return
		}


		buf, err := xml.Marshal(book)
		if err != nil {
			fmt.Fprintf(os.Stderr, "error : %s", err.Error())
			return
		}

		n, err = f.Write(buf)
		if err == nil && n < len(buf) {
			fmt.Fprintf(os.Stderr, "error : write Fail")
			return
		}
	}
}

type Task  struct{
	Id          int
	Name        string
	Name1       string
}

func main() {

	tasks := []interface{}{Task{1, "t1", "t1_1"}, Task{2, "t2", "t2_1"}, Task{3, "t3", "t3_1"}}
	MarshalExcelXml(tasks)
}




生成的.xml文件:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?><?mso-application progid="Excel.Sheet"?>
<Workbook Xmlns="urn:schemas-microsoft-com:office:spreadsheet" xmlns:o="urn:schemas-microsoft-com:office:office"
          xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet"
          xmlns:html="http://www.w3.org/TR/REC-html40" xmlns:dt="uuid:C2F41010-65B3-11d1-A29F-00AA00C14882">
    <Worksheet ss:Name="tasks">
        <Table ss:ExpandedColumnCount="3" ss:ExpandedRowCount="3" x:FullColumns="1" x:FullRows="1"
               ss:DefaultColumnWidth="60" ss:DefaultRowHeight="16">
            <Row>
                <Cell>
                    <Data ss:Type="Number">1</Data>
                </Cell>
                <Cell>
                    <Data ss:Type="String">t1</Data>
                </Cell>
                <Cell>
                    <Data ss:Type="String">t1_1</Data>
                </Cell>
            </Row>
            <Row>
                <Cell>
                    <Data ss:Type="Number">2</Data>
                </Cell>
                <Cell>
                    <Data ss:Type="String">t2</Data>
                </Cell>
                <Cell>
                    <Data ss:Type="String">t2_1</Data>
                </Cell>
            </Row>
            <Row>
                <Cell>
                    <Data ss:Type="Number">3</Data>
                </Cell>
                <Cell>
                    <Data ss:Type="String">t3</Data>
                </Cell>
                <Cell>
                    <Data ss:Type="String">t3_1</Data>
                </Cell>
            </Row>
        </Table>
    </Worksheet>
</Workbook>

直接通过excel打开:

1 t1 t1_1
2 t2 t2_1
3 t3 t3_1

转载请注明出处:

http://blog.csdn.net/eclipser1987/article/details/17691745


你可能感兴趣的:(go语言与excel的序列化与反序列化(1))