前言

xresloader 是一组用于把Excel数据结构化并导出为程序可读的数据文件的导表工具集。它包含了一系列跨平台的工具、协议描述和数据读取代码。

主要功能特点:

  • 跨平台(java 11 or upper)
  • Excel => protobuf/msgpack/lua/javascript/json/xml
  • 完整支持协议结构,包括嵌套结构和数组嵌套
  • 同时支持protobuf proto v2 和 proto v3
  • 支持导出proto枚举值到lua/javascript代码和json/xml数据
  • 支持导出proto描述信息值到lua/javascript代码和json/xml数据(支持自定义插件,方便用户根据proto描述自定义反射功能)
  • 支持导出 UnrealEngine 支持的json或csv格式,支持自动生成和导出 UnrealEngine 的 DataTable 加载代码
  • 支持别名表,用于给数据内容使用一个易读的名字
  • 支持验证器,可以在数据里直接填写proto字段名或枚举名,或者验证填入数据的是否有效
  • 支持通过protobuf协议插件控制部分输出
  • 支持自动合表,把多个Excel数据表合并成一个输出文件
  • 支持公式
  • 支持oneof,支持plain模式输入字符串转为数组或复杂结构,支持map
  • 支持空数据压缩(裁剪)或保留定长数组
  • 支持基于正则表达式分词的字段名映射转换规则
  • 支持设置数据版本号
  • Lua输出支持全局导出或导出为 require 模块或导出为 module 模块。
  • Javascript输出支持全局导出或导出为 nodejs 模块或导出为 AMD 模块。
  • 提供CLI批量转换工具(支持python 2.7/python 3 @ Windows、macOS、Linux)
  • 提供GUI批量转换工具(支持Windows、macOS、Linux)
  • CLI/GUI批量转换工具支持include来实现配置复用

xresloader 包含了多个组件,其中最主要的部分分别是。

前言

最近有几个其他项目组的童鞋给我之前的 转表工具链-xresloader 提了几个需求。然后我也根据我们近期一些需求点对转表工具链一起给这套工具做了点功能增强和细节上的一些改进。 这篇blog差不多是这些东西的 CHANGELOG了吧。

插件和协议和CI

对一些复杂的需求,使用protobuf插件机制比配置在excel里描述能力要强的多。所以近期大多的新功能都是由插件配置的。但是以前 转表引擎-xresloader 的发布流程里只包含输出的jar,协议得去对应源码包里找。另外一个童鞋报给我说找 github 的release里的源码包似乎并不支持git lfs,解出来的git lfs文件只有一个版本号,所以我给CI的发布流程里加了对应版本的protocol文件的打包,当然也包括插件的protocol。

现在的web的js开发很方便啊,但是碰到iframe里的东西还是不方便看到变量的内容,所以就写了这么个看json内容的玩意,还可以当控制台输出用。

很简单,有需要以后开发新功能

/** 
 * Show json in a new page.(For debug)
 *
 * Licensed under the MIT or GPL Version 3 licenses.
 * @version 1.3
 * @author OWenT
 * @link http://www.owent.net
 * @history 
 * 		2012.12.27 
 * 			1. 改进JSON内对象循环引用时的导致的栈溢出问题
 * 			2. 引入层级路径
 * 			3. 引入锚点
 */
 
 /**
  * Object转为字符串
  * @param {Object} json Object对象 
  * @param {Number} tab 缩进数量
  * @param {Object} rules 应用规则
  * @param {String} path 当前路径
  * @return 生成的HTML
  */
function json2String(json, tab, rules, path) {
    var tabStr = "", singleTab = "    ", isClear = false;
    var txt = "";
    
    if (!rules) {
        rules = {
            id: "__json2string_process" + (new Date).getTime().toString() + (json2String.baseIndex ++),
            objs: []
        };
        isClear = true;
    }
    
    tab = tab || 1;
    if (!path) {
        path = "{ROOT}";
        txt += " ";
    }
    
    for (var i = 0; i < tab; i ++) {
        tabStr += singleTab;
    }
    
    if (!json && json !== 0) {
        txt += 'null';
    } else if (typeof(json) == "object") {
        var prefix = '{', suffix = '}';
        try {		
            if (toString.call(json).match(/array/i)) {
                prefix = '[';
                suffix = ']';
            }
        } catch(e) {
            // hoho ...
        }
        
        if (json[rules.id]) {
            txt += prefix + "此处引用 " + 
                json[rules.id] + "" + suffix;
            return txt;
        }
        json[rules.id] = path;
        rules.objs.push(json);
        
        txt += prefix + "
\r\n"; var first = true; for (var key in json) { if (key == rules.id) continue; if (first) first = false; else txt += ",
\r\n"; txt += tabStr + " " + "" + key + " : " + json2String(json[key], tab + 1, rules, path + "." + key); } txt += "
\r\n" + tabStr.substr(0, tabStr.length - singleTab.length) + suffix; } else if (typeof(json) == "string") { txt += '"' + json + '"'; } else if (typeof(json) == "number") { txt += '' + json + ''; } else if (typeof(json) == "function") { txt += '' + json + ''; } else { txt += json.toString(); } if (isClear) { for (var i = 0; i < rules.objs.length; ++ i) { delete rules.objs[i][rules.id]; } rules.objs = []; } return txt; } function showJson(json, title, windowName, dlg_opt) { json2String.baseIndex = json2String.baseIndex || 0; title = title || "Json viewer"; windowName = windowName || "result" + (new Date()).toGMTString(); if (window.jQuery && jQuery.fn && jQuery.fn.dialog) { $("
").append(json2String(json)).css({ "text-align": "left" }).dialog($.extend({ "modal": false, "title": title, "width": 640, "height": 480, "buttons": { "关闭": function() { $( this ).dialog( "close" ); } } }, dlg_opt)); } else { var wnd = window.open("about:blank", "_blank", "height=600, width=800, toolbar=no, menubar=no, resizable=yes, location=no, status=no", true); if (!wnd) alert("窗口被拦截!"); wnd.document.write("" + title + "" + json2String(json) + ""); } return wnd; }
  1. 更新对不同类型着色
  2. 如果载入了jQuery UI 则使用jQuery UI的Dialog打开,用于解决嵌套iframe时浏览器拦截问题
  3. 解决Object循环引用时栈溢出问题,同时增加引用的指向锚点

Licensed under the MIT or GPL Version 3 licenses.