XML转Lua表

前端之家收集整理的这篇文章主要介绍了XML转Lua表前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

关于XML转Lua表,我的想法是,首先摸清XML需要用到的数据的相关格式规律,然后用lua解析出来,保存为Lua表,再把表专为lua文件

了解XML

首先是我理解的XML格式

<?xml version="1.0"?> <!-- 表头 --> <Workbook <!-- 表信息 --> <!-- 省略一些细节 --> ... <Worksheet ss:Name="工作表1"> <!-- 这是我们要关注的每个小表标志 如果有多个小表就有多个这样的标志,以小表为单位 --> <Table ss:ExpandedColumnCount="6" ss:ExpandedRowCount="20" x:FullColumns="1" x:FullRows="1" ss:DefaultColumnWidth="65" ss:DefaultRowHeight="15"><!-- 不关注 --> <Row><!-- 每行信息列出来 --> <Cell ss:StyleID="s17"><Data ss:Type="String">字段英文名</Data></Cell><!-- 每列信息列出来 --> <Cell ss:StyleID="s17"><Data ss:Type="String">level</Data></Cell> <Cell ss:StyleID="s17"><Data ss:Type="String">costXP</Data></Cell> <Cell ss:StyleID="s17"><Data ss:Type="String">waterMAX</Data></Cell> <Cell ss:StyleID="s17"><Data ss:Type="String">waterrestorespeed</Data></Cell> <Cell ss:StyleID="s17"><Data ss:Type="String">levelname</Data></Cell> </Row> </Worksheet> </Workbook> 

解析

基本上就是按上面找到规则,用正则匹配与修改。 @H_301_231@ 出现过一些小问题 @H_301_231@ 1. 要跟策划先统一好规则,因为我想工具化,不想每次都手动改表。我订的规则是前五行策划需要的话放说明,不需要的话也统一空出来,万一以后突然策划想补充些什么呢?增加一行default数值配置。然后还是正式数据。 @H_301_231@ 2. cell的写法有两种

<Cell ss:StyleID="s16"/>
  <Cell ss:StyleID="s17"><Data ss:Type="Number">2</Data></Cell>

所以不能简单用”< Cell.-< /Cell>”来匹配 @H_301_231@ 类似的变成搜索”< Cell”来确定范围

lua表转lua文件

基本也不难,之前做过,所以直接拿来用。 @H_301_231@ 遇到问题: @H_301_231@ 想统一用py来调,所以又加了一个py来统一入口,py掉lua用的是lupa,安装方法

sudo pip install lupa

最后,把完整的代码贴一下

local print = print
local table = table
local string = string
local type = type
local pairs = pairs

local printAll = function(target,params)
    local targetType = type(target)
    if targetType == "table" then
        local tip = params and params.tip or "This is a Table!^_<......................................"
        local cache = {[target] = "."}
        local isHead = false

        local function dump(t,space,level)
            local temp = {}
            if not isHead then
                temp = {tip}
                isHead = true
            end
            for k,v in pairs(t) do
                local key = tostring(k)
                if type(v) == "table" then
                    table.insert(temp,string.format("%s+[%s]\n%s",string.rep(" ",level),key,dump(v,level + 1)))
                else
                    table.insert(temp,string.format("%s+[%s]%s",tostring(v)))
                end
            end
            return table.concat(temp,string.format("\n%s",space))
        end
        print(dump(target,"",0))
        print(".................................................")
    elseif targetType == "userdata" then
        return printAll(debug.getuservalue(target),{tip = "Userdata's uservalue detail:"})
    else
        print("[printAll error]: not support type")
    end
end

--Author: mixi
--Date: 2016-06-30 11:31:55
--Abstract: XmlParser xml解析工具 之前的不能用 只好重写

local XMLParsers = {}
local PREV_NAME = "t_"
local SavePath = "/Users/mixi/Desktop"

-- 一些规定
-- 第七行是字段名字,第九行是默认数值存放,第十行开始是有效数据,第一列数据是无效的
local fieldTypeLine = 7
local defaultValueLine = 9
local valueStartLine = 10
-- local invaildLineIndexTable = {min = 2,max = 5}
local valueStartRow = 2
-- 命名
local FieldInfo = {}
-- 默认数据填充
local DefaultInfo = {}
-- 主id 有的话只能有一个 且与default不能同时存在
local mainIndex = false

local function reftesh()
    FieldInfo = {}
    DefaultInfo = {}
    mainIndex = false
end

local function fieldTypeParser(cellInfo)
    FieldInfo = cellInfo
end

local function defaultValueParser(cellInfo)
    -- printAll(cellInfo)
    for rowIndex = valueStartRow,#cellInfo do
        local cellStr = cellInfo[rowIndex]
        if cellStr then
            local startPos,endPos = string.find(cellStr,"default=")
            if endPos then
                value = string.sub(cellStr,endPos + 1)
                local newValue = tonumber(value)
                DefaultInfo[rowIndex] = newValue or value
            elseif not mainIndex then
                startPos,"main")
                if startPos then
                    mainIndex = FieldInfo[rowIndex]
                end
            end
        end
    end
end

local function enumParser(rowInfo)
end

local function fullDataFromInfo(info)
    local t = {}
    for index,value in ipairs(FieldInfo) do
        if index >= valueStartRow then
            local data = info[index]
            if not data and DefaultInfo[index] then
                data = DefaultInfo[index]
            end
            t[value] = data
        end
    end
    -- printAll(t)
    return t
end

local file = false
local function doWrite(msg,file)
    msg = msg .. "\n"
    file:write(msg)
end

local function write2Table(t,indent,file_handle)
    local pre = string.rep("\t",indent)
    for k,v in pairs(t) do
        if type(v) == "table" then
            if type(k) == "number" then
                doWrite(pre .. "[" .. k .. "]" .. " = {",file_handle)
                write2Table(v,indent + 1,file_handle)
                doWrite(pre .. "},",file_handle)
            elseif type(k) == "string" then
                if tonumber(k) then
                    doWrite(pre .. "[\"" .. k .. "\"] = {",file_handle)
                elseif (tonumber(string.sub(k,1,1))) then
                    doWrite(pre .. "[\"" .. k .. "\"] = {",file_handle)
                else
                    doWrite(pre .. k .. " = {",file_handle)
                end
                write2Table(v,file_handle)
            end
        elseif type(v) == "number" then
            if type(k) == "number" then
                doWrite(pre .. "[" .. k .. "]" .. " = " .. v .. ",file_handle)
            elseif type(k) == "string" then
                if tonumber(k) then
                    doWrite(pre .. "[\"" .. k .. "\"] = " .. v .. ",1))) then
                    doWrite(pre .. "[\"" .. k .. "\"] = " .. v .. ",file_handle)
                else
                    doWrite(pre .. k .. " = " .. v .. ",file_handle)
                end
            end
        elseif type(v) == "string" then
            local text = string.gsub(v,"[\n]","")
            text = string.gsub(text,"\"","\\\"")
            if type(k) == "number" then
                doWrite(pre .. "[" .. k .. "]" .. " = \"" .. text .. "\",file_handle)
            elseif type(k) == "string" then
                if tonumber(k) then
                    doWrite(pre .. "[\"" .. k .. "\"] = \"" .. text .. "\",1))) then
                    doWrite(pre .. "[\"" .. k .. "\"] = \"" .. text .. "\",file_handle)
                else
                    doWrite(pre .. k .. " = \"" .. text .. "\",file_handle)
                end
            end
        end
    end
end

local function saveFile(tableInfo,fileName,path,des)
    local output = string.format("%s/%s.lua",fileName)

    file = assert(io.open(output,'w'))
    local des = des or ""
    doWrite(string.format("-- %s %s",des),file)
    doWrite("local root = {",file)
    write2Table(tableInfo,file)
    doWrite("}",file)
    doWrite("return root",file)
    file:close()
end

local lineVaildIndexTable = {
    [fieldTypeLine] = fieldTypeParser,[defaultValueLine] = defaultValueParser,}

local function splitStr(str,sign)
    local info = {}
    local startPos,endPos = 0,0
    local signLength = string.len(sign)
    local function getSplitInfo()
        startPos = string.find(str,sign,endPos + 1)
        if not startPos then
            return 
        end
        endPos = string.find(str,startPos + signLength)
        if endPos then 
            endPos = endPos - 1
        else
            endPos = string.len(str)
        end
        return string.sub(str,startPos,endPos)
    end
    local splitInfo = getSplitInfo()
    while splitInfo do
        table.insert(info,splitInfo)
        splitInfo = getSplitInfo()
    end
    return info
end

local function filterRowStr(rowStr)
    local info = {}
    local cellIndex = 0
    -- 由于不是一定以</Cell>结尾 还有以/>结尾
    local cellSign = "<Cell"
    local cellStrInfo = splitStr(rowStr,cellSign)
    -- print("cellStrInfo")
    -- printAll(cellStrInfo)
    for i,cellStr in ipairs(cellStrInfo) do
        -- 找到row信息
        string.gsub(
            cellStr,"<Cell.->",function(str)
                local _,pos = string.find(str,"ss:Index")
                if pos then 
                    local startPos,endPos = string.find(str,"\".-\"",pos + 1)
                    cellIndex = string.sub(str,startPos + 1,endPos - 1)
                    cellIndex = tonumber(cellIndex)
                else
                    cellIndex = cellIndex + 1
                end
            end
        )

        local offset = cellIndex - (#info + 1)
        if offset > 0 then
            for i = 1,offset do
                table.insert(info,false)
            end
        end

        if cellIndex < valueStartRow then
            table.insert(info,false)
        else
            local value = false
            -- 解析data
            local prevPos,prevEndPos = string.find(cellStr,"<Data.->")
            local suffixPos,suffixEndPos = string.find(cellStr,"</Data>")
            if prevEndPos and suffixPos then
                local data = string.sub(cellStr,prevEndPos + 1,suffixPos - 1)
                if data then
                    local dataType
                    local str = string.sub(cellStr,prevPos,prevEndPos)
                    string.gsub(str,function(s) dataType = string.sub(s,2,-2) end)
                    if dataType and dataType == "Number" then
                        data = tonumber(data)
                    end
                    -- print("dataTypedataType",dataType,data)
                    value = data
                end
            end
            table.insert(info,value)
        end
    end
    return info
end

local function parseXmlText(xmlText)
    local xmlInfo = {}
    local dataInfo = {}

    string.gsub(
        xmlText,"<Worksheet .-</Worksheet>",function(ss)
            -- 找表名
            local name,des = false
            string.gsub(
                ss,"<Worksheet.->",function(nameStr)
                    local bracketPos = string.find(nameStr,"%(")
                    if bracketPos then
                        local startPos,endPos = string.find(nameStr,"\".-\"")
                        des = string.sub(nameStr,bracketPos - 1)
                        string.gsub(nameStr,"%(.-%)",function(str) name = string.sub(str,-2) end)
                    end
                end
            )
            print("文件名",name)
            -- 有名字的才有效
            if name then
                local dataTable = {}
                reftesh()
                local rowSign = "<Row"
                local rowStrInfo = splitStr(ss,rowSign)

                -- 枚举另外解析
                if name == "enum" then
                    local enumName,enumInfo
                    local enumNameIndex,enumDesIndex,enumValueIndex = 2,3,4
                    local rowMaxIndex = #rowStrInfo
                    for lineIndex,rowStr in ipairs(rowStrInfo) do
                        local info = filterRowStr(rowStr)
                        -- printAll(info)
                        if info[enumNameIndex] then
                            if not enumName then
                                enumName = info[enumNameIndex]
                                enumInfo = {}
                            else
                                enumInfo[info[enumNameIndex]] = tonumber(info[enumValueIndex])
                            end
                        elseif enumName and enumInfo then
                            dataTable[enumName] = enumInfo
                            enumName = false
                            enumInfo = {}
                        end
                        -- 最后一项的处理
                        if lineIndex == rowMaxIndex and not dataTable[enumName] then
                            dataTable[enumName] = enumInfo
                        end
                    end
                else
                    -- 表名
                    name = string.format("%s%s",PREV_NAME,name)
                    -- printAll(lineVaildIndexTable)
                    for lineIndex,rowStr in ipairs(rowStrInfo) do
                        if lineVaildIndexTable[lineIndex] then
                            local info = filterRowStr(rowStr)
                            lineVaildIndexTable[lineIndex](info)
                        elseif lineIndex >= valueStartLine then
                            local info = filterRowStr(rowStr)
                            local newData = fullDataFromInfo(info)
                            table.insert(dataTable,newData)
                        end
                    end
                    -- 更换index 不能有重复,重复的就先覆盖吧
                    if mainIndex then
                        local newDataTable = {}
                        for i,v in ipairs(dataTable) do
                            if v[mainIndex] and newDataTable[v[mainIndex]] then
                                print("警告,有个数据重复了",mainIndex,v[mainIndex],i)
                            end
                            newDataTable[v[mainIndex]] = v
                        end
                        dataTable = newDataTable
                    end
                end
                saveFile(dataTable,name,SavePath,des)                        
            end
        end
    )
end

function XMLParsers.loadFile(xmlFileFullPath,saveFilePath)
    local hFile,err = io.open(xmlFileFullPath,"r");
    if saveFilePath then
        SavePath = saveFilePath
    end
    if hFile and not err then
        local xmlText = hFile:read("*a"); -- read file content
        io.close(hFile);
        return parseXmlText(xmlText),nil;
    else
        print(err)
        return nil
    end
end

return XMLParsers

创建py

#!/usr/bin/env python
# coding=utf-8

import os
import sys
import lupa

# 获取基本路径前缀
dir = os.path.abspath(os.path.dirname(__file__))

# xmlParams
LUA_REQUIRE_DIR = os.path.join(dir,"../xml2Table")
lua = lupa.LuaRuntime()
lua.execute("package.path = package.path .. \";\" ..\"%s/?.lua\"" % LUA_REQUIRE_DIR)
XMLParsers = lua.require('XMLParsers')

# 配置表xml-->lua,生成在临时目录
def convertConfig(configSrc,configTempOutPut):
    for f in os.listdir(configSrc):
        fs = f.split(".")
        if len(fs) > 1 and fs[1] == "xml":
            # print f
            XMLParsers.loadFile(
                os.path.join(configSrc,f),configTempOutPut
            )

configSrc = os.path.join(dir,"../../public/配置表")
configTempOutPut = os.path.join(dir,"../../client/src/game/Resource/config/config")
convertConfig(configSrc,configTempOutPut)

猜你在找的XML相关文章