将一个html标记 转 json串

来源:互联网 发布:mac用户名怎么改 编辑:程序博客网 时间:2024/05/16 08:29
 /** * 将一个html标记 转 json串 * @param {String} html 要处理的html标签。html串必须有且仅有一个根节点。 * @param {int} indent_str_count 起始缩进符个数 * @param {String} indent_str 缩进符,默认tab键 * @param {Object} indent 缩进对象 * @return {String} json *                 { *                     "tag": "标签名", *                     "attrs": {"属性名": "属性值", ...}, *                     "content": ["标签内容" | json  | [json数组]]     *                 } *         出错返回结果: {"error": "html串必须包括一个根节点"} * @test 嵌套(nested):html2json("<table><tr><td class=\"popupmenu_option\" onclick=\"Do('detail')\">详细结构</td></tr><tr><td class=\"popupmenu_option\" onclick=\"Do('rawdata')\">原始邮件</td><tr><td class=\"popupmenu_option\" onclick=\"Do('detail')\">详细结构</td></tr></tr></table>") * @test 同级(sibling):html2json("<tr><td class=\"popupmenu_option\" onclick=\"Do('detail')\">详细结构</td></tr><tr><td class=\"popupmenu_option\" onclick=\"Do('rawdata')\">原始邮件</td></tr>") * @create xiaolong8 @ 2012-6-7 16:30:48 * @modify [content字段的文本添加对"进行替换为\"的转义形式] by [堅] @ [2012-6-8 9:03:36] * @modify [content字段添加:对标签内容若仍为html标签,则继续转json] by [堅] @ [2012-6-8 9:22:32] * @modify [添加json串缩进显示] by [堅] @ [2012-6-8 11:54:27] * @modify [属性组(attrs)JSON生成时,按空格分离属性到数组(.split(/\s+/))的方式改为按正则匹配到数组(.match(/\w+=(?:"(?:[^"]|(?:\"))+?"|'(?:[^']|(?:\'))+?')/g);)的方式] by [堅] @ [2012年6月11日11:51:56] * @modify [添加对用户传入的html串做根/嵌套标签和同级标签的处理] by [堅] @ [2012-6-11 17:25:07] * @modify [log] by [user] @ [time] * @TODO: input img 这类单行标签未处理 */function html2json(html, indent_str_count, indent_str, indent) {    /// 常量设置    var HTML_TAG_NAME = "tag";    var HTML_TAG_ATTRIBUTES = "attrs";    var HTML_TAG_CONTENT = "content";    // HTML元素组    var htmlEls = null;    // 是否首次(非递归)执行。indent为空说明是首次调用    var isFirstRun = indent ? false : true;        /// 验证是否为字符串,若是去除其前后导空格    if (!html || typeof(html) != "string") {        return null;    }    String.prototype.trim = String.prototype.trim ||                 function(){return this.replace(/^\s+|\s+$/g, "");};    html = html.trim();        /// 同级标签解析,若match后长度等于1,说明不是同级标签 */    htmlEls = html.match(/<(\w+)([^>]*)>(.*?)<\/\1>/gi);    if (!htmlEls) {        // 首次调用(非递归),即html不符合要求,直接返null;否则生成content字段的内容并返回        return isFirstRun ? null : "\"" + html.replace(/\"/g, "\\\"") + "\"";    }                /// 设置各种默认值    // 默认缩进1个字符    indent_str_count = indent_str_count || 1;    // 默认缩进字符为tab键    indent_str = indent_str || "\t";        // 缩进对象(共用)    indent = indent || {            "strings": [],            "str": indent_str,             /**             * 获取count个缩进字符             * p.s. 写完发现这个貌似有点像传说中的享元模式,昨天刚看的,没想到无意中写出来了。             *      于是果断把函数名由get改为了factory。             *      strings数组里存放的就是共享的缩进单元,相同个数的缩进符 共享 同一个缩进单元。             *      如,factory(5)都是 共享 strings[4]单元。             * @param {int} count             * @return {String} count个缩进字符             * @test              * @create 堅 @ 2012-6-8 10:26:32             * @modify [log] by [user] @ [time]             */            "factory": function(count) {                         var index = count - 1;                         if (!this.strings[index]) {                             var string = new Array(count + 1).join(this.str);                             this.strings[index] = string;                         }                         return this.strings[index];                },            "getIndentStr": function() {                    return this.str || "\t";;                }        };        if (htmlEls.length > 1) {    /// html串内含多个同级标签        if (isFirstRun) {            // 用户传进的html串为同级标签。            return {"error": "html串必须包括一个根节点"};        }    var elsJson = "["    for (var i = 0; ; i++) {        elsJson += html2json(htmlEls[i], indent_str_count + 1, indent.getIndentStr(), indent);        if (i >= htmlEls.length -1) {            elsJson += "\n";            break;        }        elsJson += ", ";    }    elsJson += indent.factory(indent_str_count - 1) + "]";    return elsJson;    } else if (htmlEls.length == 1) {        /// html串为一个根标签 或是 一组嵌套标签        // 根标签或嵌套标签解析        htmlEls = html.match(/^\s*<(\w+)([^>]*)>(.*)<\/\1>\s*$/gi);        var tag = RegExp.$1;        var content = RegExp.$3;        var attrs = RegExp.$2.trim().match(/\w+=(?:"(?:[^"]|(?:\"))+?"|'(?:[^']|(?:\'))+?')/g);    var json = "";        json = "{\n" +        indent.factory(indent_str_count) + "\"" + HTML_TAG_NAME + "\": \"" + tag + "\", \n" +        indent.factory(indent_str_count) + "\"" + HTML_TAG_ATTRIBUTES + "\": " +             (function() {                var attrsJson = "\"\"";                if (attrs && attrs.length) {                    attrsJson = "{\n";                    for (var i = 0; ; i++) {                        attrPair = attrs[i].split("=");                        name = attrPair[0];                        value = attrPair[1].replace(/^['"]?|['"]?$/g, "");                        attrsJson += indent.factory(indent_str_count + 1) +                                         "\"" + name + "\": \"" + value + "\"";                        if (i >= attrs.length - 1) {                            attrsJson += "\n";                            break;                        }                        attrsJson += ", \n";                    }                    attrsJson += indent.factory(indent_str_count)+ "}";                }                return attrsJson;            })()  + ", \n" +        indent.factory(indent_str_count) + "\"" + HTML_TAG_CONTENT + "\": " +             html2json(content, indent_str_count + 1, indent.getIndentStr(), indent) + "\n" +         indent.factory(indent_str_count-1) + "}";        return json;    }}