一个退役中校教你如何用go语言写一个基于B+树的json数据库(进阶篇)之json字符串解析为BsTr结构(二)

代码地址:https://gitee.com/lineofsight/resob

导读:一个退役中校教你如何用go语言写一个基于B+树的json数据库(进阶篇)之json字符串解析为BsTr结构(一)-CSDN博客

二、转为中间结构——BsTr结构体

// flag of PUTJSON and GETJSON used in GetJsonKvs
const (
	PUTJSON = 0x0001
	GETJSON = 0x0002
	SETTMPL = 0x0004
)

// ToBsTr get key-vlaues from json, and collect into a Bstr struct
// value be collect as string,int64,float64,bool,bytes in a BsTr struct
// null value be stored as a nil []byte
func (jr *JsonParser) ToBsTr(flag int) *BsTr {
	jsonbstr := new(BsTr)
	jsonbstr.Init("", "")
	_, _, jsonbstr = jr.jts[0].ToBsTr("", "", jsonbstr, flag)
	jsonbstr.afterPutAnyByKey(":")
	jsonbstr.afterPutAnyByKey(".")
	return jsonbstr
}

func (jr *JsonParser) ToNonidsBsTr() *BsTr {
	jsonbstr := new(BsTr)
	jsonbstr.InitWithNonids("", "", true)
	jsonbstr = jr.jts[0].ToNonidsBsTr(jsonbstr)
	return jsonbstr
}

func (jr *JsonParser) ToNocheckBsTr(flag int) *BsTr {
	jsonbstr := new(BsTr)
	jsonbstr.Init("", "")
	_, _, jsonbstr = jr.jts[0].ToNocheckBsTrs("", "", jsonbstr, flag)
	jsonbstr.afterPutAnyByKey(":")
	jsonbstr.afterPutAnyByKey(".")
	return jsonbstr
}

// ToBsTr get key-vlaues from json, and collect into a Bstr struct
// key-value format collect in a BsTr struct same as or analogy/compatible
// with a strcut be put into a BsTr struct when call the PutAnyByKey method
// as follows: (details about PutAnyByKey in ip.go)
// can be used by GetAnyByKey method to unserialize to a struct
// nids[0] format: field:tn(arr is index:tn)
// nids[1] format: tn.field(arr is tn.index)
// nids[2] is ""
func (jt *JsonToken) ToBsTr(colonStr, dotStr string, jsonBstr *BsTr, flag int) (string, string, *BsTr) {
	if jt.child == nil { //child is nil, indicates is a value-filed or a arr value-item
		switch jt.jtt {
		case JsonStrField:
			cstr := jt.jttstr + ":" + colonStr
			dstr := dotStr + "." + jt.jttstr
			if jt.equity[0].jtt != JsonNULL { //not a null
				jsonBstr.PutString(jt.equity[0].jttstr, cstr, dstr, "")
			} else {
				jsonBstr.PutString("", cstr, dstr, "") //null string = ""
			}
		case JsonNumField:
			//not proceed scientific notation
			if !strings.Contains(jt.equity[0].jttstr, ".") {
				cstr := jt.jttstr + ":" + colonStr
				dstr := dotStr + "." + jt.jttstr
				ns, _ := strconv.ParseInt(jt.equity[0].jttstr, 10, 0)
				if jt.equity[0].jtt != JsonNULL {
					jsonBstr.PutInt64(ns, cstr, dstr, "")
				} else {
					jsonBstr.PutInt64(0, cstr, dstr, "") //null int64 = 0
				}
			} else {
				cstr := jt.jttstr + ":" + colonStr
				dstr := dotStr + "." + jt.jttstr
				ns, _ := strconv.ParseFloat(jt.equity[0].jttstr, 64)
				if jt.equity[0].jtt != JsonNULL {
					jsonBstr.PutFloat64(ns, cstr, dstr, "")
				} else {
					jsonBstr.PutFloat64(0.0, cstr, dstr, "") //null float64 = 0.0
				}
			}
		case JsonBoolField:
			cstr := jt.jttstr + ":" + colonStr
			dstr := dotStr + "." + jt.jttstr
			ns, e := strconv.ParseBool(jt.equity[0].jttstr)
			if e != nil {
				jsonBstr.PutBool(false, cstr, dstr, "")
			} else {
				jsonBstr.PutBool(ns, cstr, dstr, "")
			}
		case JsonArrStr:
			jsonBstr.PutString(jt.jttstr, colonStr, dotStr, "")
		case JsonArrNum:
			if !strings.Contains(jt.jttstr, ".") {
				ns, _ := strconv.ParseInt(jt.jttstr, 10, 0)
				jsonBstr.PutInt64(ns, colonStr, dotStr, "")
			} else {
				ns, _ := strconv.ParseFloat(jt.jttstr, 64)
				jsonBstr.PutFloat64(ns, colonStr, dotStr, "")
			}
		case JsonArrNULL: //null only proceeded as nil of []byte in a arr
			jsonBstr.PutBytes([]byte(nil), colonStr, dotStr, "")
		case JsonArrTrue, JsonArrFalse:
			ns, e := strconv.ParseBool(jt.jttstr)
			if e != nil {
				jsonBstr.PutBool(false, colonStr, dotStr, "")
			} else {
				jsonBstr.PutBool(ns, colonStr, dotStr, "")
			}
		}
	} else {
		switch jt.jtt {
		case JsonBraceBegin: //first call, no prefix
			for i := 0; i < len(jt.child); i++ {
				colonStr, dotStr, jsonBstr = jt.child[i].ToBsTr("", "", jsonBstr, flag)
			}
		case JsonBracketBegin: //first call, no prefix, should ToNocheckBsTrs
			for i := 0; i < len(jt.child); i++ {
				colonStr, dotStr, jsonBstr = jt.child[i].ToBsTr("", "", jsonBstr, flag)
			}
		case JsonObjField:
			ocolonstr := colonStr
			odotstr := dotStr
			for i := 0; i < len(jt.child); i++ {
				if flag == PUTJSON || flag == GETJSON || flag == SETTMPL { //flag
					if !(strings.Compare(strings.ToLower(jt.jttstr), JSONDTDELOPS) == 0 || strings.Compare(strings.ToLower(jt.jttstr), JSONDTUPDOPS) == 0 || strings.Compare(strings.ToLower(jt.jttstr), JSONDTPUTOPS) == 0 || strings.Compare(strings.ToLower(jt.jttstr), JSONDTGETOPS) == 0 || strings.Compare(strings.ToLower(jt.jttstr), JSONDTSETOPS) == 0) {
						colonStr, dotStr, jsonBstr = jt.child[i].ToBsTr(jt.jttstr+":"+ocolonstr, odotstr+"."+jt.jttstr, jsonBstr, flag)
					} else { //flag string be not add to prefix or suffix
						colonStr, dotStr, jsonBstr = jt.child[i].ToBsTr("", "", jsonBstr, flag)
					}
				} else {
					colonStr, dotStr, jsonBstr = jt.child[i].ToBsTr(jt.jttstr+":"+ocolonstr, odotstr+"."+jt.jttstr, jsonBstr, flag)
				}
			}
		case JsonArrField:
			ocolonstr := colonStr
			odotstr := dotStr
			for i := 0; i < len(jt.child); i++ {
				is := strconv.FormatInt(int64(i), 10)                      //index add as a field prefix
				if flag == PUTJSON || flag == GETJSON || flag == SETTMPL { //flag string be not add to prefix or suffix
					if !(strings.Compare(strings.ToLower(jt.jttstr), JSONDTPUTOPS) == 0 || strings.Compare(strings.ToLower(jt.jttstr), JSONDTGETOPS) == 0 || strings.Compare(strings.ToLower(jt.jttstr), JSONDTSETOPS) == 0) {
						colonStr, dotStr, jsonBstr = jt.child[i].ToBsTr(is+":"+jt.jttstr+":"+ocolonstr, odotstr+"."+jt.jttstr+"."+is, jsonBstr, flag)
					} else {
						colonStr, dotStr, jsonBstr = jt.child[i].ToBsTr(is+":"+ocolonstr, odotstr+"."+is, jsonBstr, flag)
					}
				} else {
					colonStr, dotStr, jsonBstr = jt.child[i].ToBsTr(is+":"+jt.jttstr+":"+ocolonstr, odotstr+"."+jt.jttstr+"."+is, jsonBstr, flag)
				}
			}
		case JsonObjStart:
			ocolonstr := colonStr
			odotstr := dotStr
			for i := 0; i < len(jt.child); i++ {
				colonStr, dotStr, jsonBstr = jt.child[i].ToBsTr(ocolonstr, odotstr, jsonBstr, flag)
			}
		case JsonArrStart:
			ocolonstr := colonStr
			odotstr := dotStr
			for i := 0; i < len(jt.child); i++ {
				is := strconv.FormatInt(int64(i), 10) //index add as a field prefix
				colonStr, dotStr, jsonBstr = jt.child[i].ToBsTr(is+":"+ocolonstr, odotstr+"."+is, jsonBstr, flag)
			}
		}
	}
	return colonStr, dotStr, jsonBstr
}

// ToBsTrBonids get key-vlaues from json, and collect into a Bstr struct with true nonids
func (jt *JsonToken) ToNonidsBsTr(jsonBstr *BsTr) *BsTr {
	if jt.child == nil { //child is nil, indicates is a value-filed or a arr value-item
		switch jt.jtt {
		case JsonStrField:
			if jt.equity[0].jtt != JsonNULL { //not a null
				jsonBstr.PutString(jt.equity[0].jttstr, "", "", "")
			} else {
				jsonBstr.PutString("", "", "", "") //null string = ""
			}
		case JsonNumField:
			//not proceed scientific notation
			if !strings.Contains(jt.equity[0].jttstr, ".") {
				ns, _ := strconv.ParseInt(jt.equity[0].jttstr, 10, 0)
				if jt.equity[0].jtt != JsonNULL {
					jsonBstr.PutInt64(ns, "", "", "")
				} else {
					jsonBstr.PutInt64(0, "", "", "") //null int64 = 0
				}
			} else {
				ns, _ := strconv.ParseFloat(jt.equity[0].jttstr, 64)
				if jt.equity[0].jtt != JsonNULL {
					jsonBstr.PutFloat64(ns, "", "", "")
				} else {
					jsonBstr.PutFloat64(0.0, "", "", "") //null float64 = 0.0
				}
			}
		case JsonBoolField:
			ns, e := strconv.ParseBool(jt.equity[0].jttstr)
			if e != nil {
				jsonBstr.PutBool(false, "", "", "")
			} else {
				jsonBstr.PutBool(ns, "", "", "")
			}
		case JsonArrStr:
			jsonBstr.PutString(jt.jttstr, "", "", "")
		case JsonArrNum:
			if !strings.Contains(jt.jttstr, ".") {
				ns, _ := strconv.ParseInt(jt.jttstr, 10, 0)
				jsonBstr.PutInt64(ns, "", "", "")
			} else {
				ns, _ := strconv.ParseFloat(jt.jttstr, 64)
				jsonBstr.PutFloat64(ns, "", "", "")
			}
		case JsonArrNULL: //null only proceeded as nil of []byte in a arr
			jsonBstr.PutBytes([]byte(nil), "", "", "")
		case JsonArrTrue, JsonArrFalse:
			ns, e := strconv.ParseBool(jt.jttstr)
			if e != nil {
				jsonBstr.PutBool(false, "", "", "")
			} else {
				jsonBstr.PutBool(ns, "", "", "")
			}
		}
	} else {
		switch jt.jtt {
		case JsonBraceBegin: //first call, no prefix
			for i := 0; i < len(jt.child); i++ {
				jsonBstr = jt.child[i].ToNonidsBsTr(jsonBstr)
			}
		case JsonBracketBegin: //first call, no prefix, should ToNocheckBsTrs
			for i := 0; i < len(jt.child); i++ {
				jsonBstr = jt.child[i].ToNonidsBsTr(jsonBstr)
			}
		case JsonObjField:
			for i := 0; i < len(jt.child); i++ {
				jsonBstr = jt.child[i].ToNonidsBsTr(jsonBstr)
			}
		case JsonArrField:
			for i := 0; i < len(jt.child); i++ {
				jsonBstr = jt.child[i].ToNonidsBsTr(jsonBstr)
			}
		case JsonObjStart:
			for i := 0; i < len(jt.child); i++ {
				jsonBstr = jt.child[i].ToNonidsBsTr(jsonBstr)
			}
		case JsonArrStart:
			for i := 0; i < len(jt.child); i++ {
				jsonBstr = jt.child[i].ToNonidsBsTr(jsonBstr)
			}
		}
	}
	return jsonBstr
}

// ToNocheckBsTrs for FindJson, maybe has the same field
// usually, a BsTr struct donot permit same field
func (jt *JsonToken) ToNocheckBsTrs(colonStr, dotStr string, jsonBstr *BsTr, flag int) (string, string, *BsTr) {
	if jt.child == nil { //child is nil, indicates is a value-filed or a arr value-item
		switch jt.jtt {
		case JsonStrField:
			cstr := jt.jttstr + ":" + colonStr
			dstr := dotStr + "." + jt.jttstr
			if jt.equity[0].jtt != JsonNULL { //not a null
				jsonBstr.NocheckPutString(jt.equity[0].jttstr, cstr, dstr, "")
			} else {
				jsonBstr.NocheckPutString("", cstr, dstr, "") //null string = ""
			}
		case JsonNumField:
			//not proceed scientific notation
			if !strings.Contains(jt.equity[0].jttstr, ".") {
				cstr := jt.jttstr + ":" + colonStr
				dstr := dotStr + "." + jt.jttstr
				ns, _ := strconv.ParseInt(jt.equity[0].jttstr, 10, 0)
				if jt.equity[0].jtt != JsonNULL {
					jsonBstr.NocheckPutInt64(ns, cstr, dstr, "")
				} else {
					jsonBstr.NocheckPutInt64(0, cstr, dstr, "") //null int64 = 0
				}
			} else {
				cstr := jt.jttstr + ":" + colonStr
				dstr := dotStr + "." + jt.jttstr
				ns, _ := strconv.ParseFloat(jt.equity[0].jttstr, 64)
				if jt.equity[0].jtt != JsonNULL {
					jsonBstr.NocheckPutFloat64(ns, cstr, dstr, "")
				} else {
					jsonBstr.NocheckPutFloat64(0.0, cstr, dstr, "") //null float64 = 0.0
				}
			}
		case JsonBoolField:
			cstr := jt.jttstr + ":" + colonStr
			dstr := dotStr + "." + jt.jttstr
			ns, e := strconv.ParseBool(jt.equity[0].jttstr)
			if e != nil {
				jsonBstr.NocheckPutBool(false, cstr, dstr, "")
			} else {
				jsonBstr.NocheckPutBool(ns, cstr, dstr, "")
			}
		case JsonArrStr:
			jsonBstr.NocheckPutString(jt.jttstr, colonStr, dotStr, "")
		case JsonArrNum:
			if !strings.Contains(jt.jttstr, ".") {
				ns, _ := strconv.ParseInt(jt.jttstr, 10, 0)
				jsonBstr.NocheckPutInt64(ns, colonStr, dotStr, "")
			} else {
				ns, _ := strconv.ParseFloat(jt.jttstr, 64)
				jsonBstr.NocheckPutFloat64(ns, colonStr, dotStr, "")
			}
		case JsonArrNULL: //null only proceeded as nil of []byte in a arr
			jsonBstr.NocheckPutBytes([]byte(nil), colonStr, dotStr, "")
		case JsonArrTrue, JsonArrFalse:
			ns, e := strconv.ParseBool(jt.jttstr)
			if e != nil {
				jsonBstr.NocheckPutBool(false, colonStr, dotStr, "")
			} else {
				jsonBstr.NocheckPutBool(ns, colonStr, dotStr, "")
			}
		}
	} else {
		switch jt.jtt {
		case JsonBraceBegin: //first call, no prefix
			for i := 0; i < len(jt.child); i++ {
				colonStr, dotStr, jsonBstr = jt.child[i].ToNocheckBsTrs("", "", jsonBstr, flag)
			}
		case JsonBracketBegin: //first call, no prefix
			for i := 0; i < len(jt.child); i++ {
				colonStr, dotStr, jsonBstr = jt.child[i].ToNocheckBsTrs("", "", jsonBstr, flag)
			}
		case JsonObjField:
			ocolonstr := colonStr
			odotstr := dotStr
			for i := 0; i < len(jt.child); i++ {
				if flag == PUTJSON || flag == GETJSON { //flag
					if !(strings.Compare(strings.ToLower(jt.jttstr), JSONDTPUTOPS) == 0 || strings.Compare(strings.ToLower(jt.jttstr), JSONDTGETOPS) == 0) {
						colonStr, dotStr, jsonBstr = jt.child[i].ToNocheckBsTrs(jt.jttstr+":"+ocolonstr, odotstr+"."+jt.jttstr, jsonBstr, flag)
					} else { //flag string be not add to prefix or suffix
						colonStr, dotStr, jsonBstr = jt.child[i].ToNocheckBsTrs("", "", jsonBstr, flag)
					}
				} else {
					colonStr, dotStr, jsonBstr = jt.child[i].ToNocheckBsTrs(jt.jttstr+":"+ocolonstr, odotstr+"."+jt.jttstr, jsonBstr, flag)
				}
			}
		case JsonArrField:
			ocolonstr := colonStr
			odotstr := dotStr
			for i := 0; i < len(jt.child); i++ {
				is := strconv.FormatInt(int64(i), 10)   //index add as a field prefix
				if flag == PUTJSON || flag == GETJSON { //flag string be not add to prefix or suffix
					if !(strings.Compare(strings.ToLower(jt.jttstr), JSONDTPUTOPS) == 0 || strings.Compare(strings.ToLower(jt.jttstr), JSONDTGETOPS) == 0) {
						colonStr, dotStr, jsonBstr = jt.child[i].ToNocheckBsTrs(is+":"+jt.jttstr+":"+ocolonstr, odotstr+"."+jt.jttstr+"."+is, jsonBstr, flag)
					} else {
						colonStr, dotStr, jsonBstr = jt.child[i].ToNocheckBsTrs(is+":"+ocolonstr, odotstr+"."+is, jsonBstr, flag)
					}
				} else {
					colonStr, dotStr, jsonBstr = jt.child[i].ToNocheckBsTrs(is+":"+jt.jttstr+":"+ocolonstr, odotstr+"."+jt.jttstr+"."+is, jsonBstr, flag)
				}
			}
		case JsonObjStart:
			ocolonstr := colonStr
			odotstr := dotStr
			for i := 0; i < len(jt.child); i++ {
				colonStr, dotStr, jsonBstr = jt.child[i].ToNocheckBsTrs(ocolonstr, odotstr, jsonBstr, flag)
			}
		case JsonArrStart:
			ocolonstr := colonStr
			odotstr := dotStr
			for i := 0; i < len(jt.child); i++ {
				is := strconv.FormatInt(int64(i), 10) //index add as a field prefix
				colonStr, dotStr, jsonBstr = jt.child[i].ToNocheckBsTrs(is+":"+ocolonstr, odotstr+"."+is, jsonBstr, flag)
			}
		}
	}
	return colonStr, dotStr, jsonBstr
}

注:中间结构体BsTr,避免了使用反射进行反序列化,提高了效率;ToBsTr将json字符串转化为普通的BsTr中间结构,对于每一个值不允许存在重复的ID;ToNonidsBsTr将json字符串转化为对值没有ID、field和描述的BsTr中间结构;ToNochecksBsTrs允许多个json字符串转化到同一个BsTr中间结构,运行存在重复的ID。

s := "{\"put\":{\"putjsontest\":{\"aaa\":\"sdf\tsdfs\\dfe29asdf\",\"aaab\":true,\"arrarrstrct\":{\"nnn\":-1234567890,\"ccc\":[[\"sdf\tsdfs\\dfe29asdf\",\"nmbndfvdfgfdg\"],[\"sdf\tsdfs\\dfe29asdf\",\"poiuiyyttt\"]]},\"ddd\":\"sdf\tsdfs\\dfe29asdf\",\"fff\":false,\"comboolarr\":[{\"boolarr0\":[true,false]},{\"boolarr1\":[true,false]}]}}}"

   其中间结构(使用了PUTJSON标志)打印如下:

&{false  [] false false 922 0 8209 0 0 [16 16 0 15 15 0 35 35 0 35 35 0 35 35 0 35 35 0] [] [] [] [27 27 0] [] [] [] [] [] [] [] [] [15 15 0 31 31 0 31 31 0 31 31 0 31 31 0 15 15 0] [] [16 16 13 16 10 16] [] [] [true false true false true false] [aaab:putjsontest putjsontest.aaab  fff:putjsontest putjsontest.fff  0:boolarr0:0:comboolarr:putjsontest putjsontest.comboolarr.0.boolarr0.0  1:boolarr0:0:comboolarr:putjsontest putjsontest.comboolarr.0.boolarr0.1  0:boolarr1:1:comboolarr:putjsontest putjsontest.comboolarr.1.boolarr1.0  1:boolarr1:1:comboolarr:putjsontest putjsontest.comboolarr.1.boolarr1.1 ] [] [] [] [] [] [] [-1234567890] [nnn:arrarrstrct:putjsontest putjsontest.arrarrstrct.nnn ] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [] [sdf	sdfsfe29asdf sdf	sdfsfe29asdf nmbndfvdfgfdg sdf	sdfsfe29asdf poiuiyyttt sdf	sdfsfe29asdf] [aaa:putjsontest putjsontest.aaa  0:0:ccc:arrarrstrct:putjsontest putjsontest.arrarrstrct.ccc.0.0  1:0:ccc:arrarrstrct:putjsontest putjsontest.arrarrstrct.ccc.0.1  0:1:ccc:arrarrstrct:putjsontest putjsontest.arrarrstrct.ccc.1.0  1:1:ccc:arrarrstrct:putjsontest putjsontest.arrarrstrct.ccc.1.1  ddd:putjsontest putjsontest.ddd ] [] [] [] [] []   -1 [6 0 0 0 1 0 0 0 0 0 0 0 0 6 0 0 0 0]}

三、BsTr中间结构转为json字符串

(一)BsTr中间结构转为json语法树

// Assemble implements parser a BsTr datastruct to a JsonToken tree
// when using with the method, the BsTr must be a json processed with DissembleObj firstly, and after call ToBsTr successfully
func (cs *BsTr) Assemble(key any) *JsonToken {
	var headjts *JsonToken
	jtss := cs.AssembleBoolJsonTokenTree()
	if len(jtss) > 1 {
		headjts = jtss[0]
	}
	jtss = cs.AssembleI64JsonTokenTree()
	if len(jtss) > 1 && jtss[0].child != nil {
		if headjts != nil {
			headjts.child = append(headjts.child, jtss[0].child...)
		} else {
			headjts = jtss[0]
		}
	}
	jtss = cs.AssembleF64JsonTokenTree()
	if len(jtss) > 1 && jtss[0].child != nil {
		if headjts != nil {
			head_child_intdexes := make([]bool, len(jtss[0].child))
			for i := 0; i < len(headjts.child); i++ {
				for j := 0; j < len(jtss[0].child); j++ {
					if head_child_intdexes[j] {
						continue
					}
					if strings.Compare(headjts.child[i].jttstr, jtss[0].child[j].jttstr) == 0 {
						headjts.child[i].child = append(headjts.child[i].child, jtss[0].child[j].child...)
						head_child_intdexes[j] = true
					}
				}
			}
			for j := 0; j < len(jtss[0].child); j++ {
				if !head_child_intdexes[j] {
					headjts.child = append(headjts.child, jtss[0].child[j])
				}
			}
		} else {
			headjts = jtss[0]
		}
	}
	jtss = cs.AssembleStrJsonTokenTree()
	if len(jtss) > 1 && jtss[0].child != nil {
		if headjts != nil {
			head_child_intdexes := make([]bool, len(jtss[0].child))
			for i := 0; i < len(headjts.child); i++ {
				for j := 0; j < len(jtss[0].child); j++ {
					if head_child_intdexes[j] {
						continue
					}
					if strings.Compare(headjts.child[i].jttstr, jtss[0].child[j].jttstr) == 0 {
						headjts.child[i].child = append(headjts.child[i].child, jtss[0].child[j].child...)
					}
				}
			}
			for j := 0; j < len(jtss[0].child); j++ {
				if !head_child_intdexes[j] {
					headjts.child = append(headjts.child, jtss[0].child[j])
				}
			}
		} else {
			headjts = jtss[0]
		}
	}
	return headjts
}

注:AssembleBoolJsonTokenTree、AssembleF64JsonTokenTree和AssembleI64JsonTokenTree、AssembleStrJsonTokenTree分别将bool值、number值(分为分loat64和int64两种类型)、string值的集合转为json语法子树。

这里只贴出AssembleStrJsonTokenTree的代码:

// AssembleStrJsonTokenTree assemble a Jsontoken tree for a BsTr embeded-type strings
// only support beginning of letters IDs
// or the BsTr datastruct of jsons that begin with object, not array
// or else, an unforeseen result will be occured
func (cs *BsTr) AssembleStrJsonTokenTree() []*JsonToken {
	if len(cs.ss) > 0 {
		var jtss [][]*JsonToken
		for i := 0; i < len(cs.ss); i++ {
			if strings.Compare(cs.snids[i*3], JSONDTKEY) == 0 {
				continue
			}
			var pn []int
			var jts []*JsonToken
			count := 0
			old_lastcolon_i := len(cs.snids[i*3])
			for {
				lastcolon_i := strings.LastIndex(cs.snids[i*3][:old_lastcolon_i], ":")
				curnode_s := cs.snids[i*3][lastcolon_i+1 : old_lastcolon_i]
				if !IsNumber(curnode_s) { //cur not num
					if len(pn) == 0 {
						jts = append(jts, &JsonToken{JsonObjField, nil, nil, nil, "\"" + curnode_s + "\"", 0, nil})
						pn = append(pn, count)
						count++
					} else {
						if jts[pn[len(pn)-1]].jtt == JsonArrStart {
							//before JsonArrStart, must has a JsonArrField
							//JsonArrField include a JsonArrStart
							//rollback a JsonArrStart
							pn = pn[:len(pn)-1]
							jts = jts[:len(jts)-1]
							jts[pn[len(pn)-1]].child = jts[pn[len(pn)-1]].child[:len(jts[pn[len(pn)-1]].child)-1]
							count--
						}
						jts = append(jts, &JsonToken{JsonObjField, jts[pn[len(pn)-1]], nil, nil, "\"" + curnode_s + "\"", 0, nil})
						jts[pn[len(pn)-1]].child = append(jts[pn[len(pn)-1]].child, jts[count])
						jts[count].level = jts[pn[len(pn)-1]].level + 1
						pn = append(pn, count)
						count++
					}
					if lastcolon_i == -1 {
						jts[pn[len(pn)-1]].jtt = JsonStrField
						jts = append(jts, &JsonToken{JsonStr, nil, nil, nil, "\"" + cs.ss[i] + "\"", 0, nil})
						jts[pn[len(pn)-1]].equity = append(jts[pn[len(pn)-1]].equity, jts[count])
						break
					}
				} else { // cur num
					if len(pn) == 0 {
						log.Println("Not supportted BsTr pattern")
						return nil
					}
					if jts[pn[len(pn)-1]].jtt == JsonObjField {
						jts[pn[len(pn)-1]].jtt = JsonArrField
					}
					if lastcolon_i != -1 {
						jts = append(jts, &JsonToken{JsonArrStart, jts[pn[len(pn)-1]], nil, nil, curnode_s, 0, nil})
						jts[pn[len(pn)-1]].child = append(jts[pn[len(pn)-1]].child, jts[count])
						jts[count].level = jts[pn[len(pn)-1]].level + 1
						pn = append(pn, count)
						count++
					}
					if lastcolon_i == -1 {
						jts = append(jts, &JsonToken{JsonArrStr, jts[pn[len(pn)-1]], nil, nil, "\"" + cs.ss[i] + "\"", 0, nil})
						jts[pn[len(pn)-1]].child = append(jts[pn[len(pn)-1]].child, jts[count])
						jts[count].level = jts[pn[len(pn)-1]].level + 1
						break
					}
				}
				old_lastcolon_i = lastcolon_i
			}
			jtss = append(jtss, jts)
		}
		if len(jtss) == 1 {
			return jtss[0]
		}
		//only for here-- because of being sorted
		for i := 1; i < len(jtss); i++ {
			if len(jtss[i][0].child) > 0 {
			__merge__:
				for k := len(jtss[0][0].child) - 1; k >= 0; k-- {
					child0 := jtss[0][0].child[k]
					childi := jtss[i][0].child[0]
					for {
						if child0 != nil {
							if child0.jtt != childi.jtt {
								child0.parent.child = append(child0.parent.child, childi)
								childi.parent = child0.parent
								break __merge__
							} else if strings.Compare(child0.jttstr, childi.jttstr) != 0 {
								child0.parent.child = append(child0.parent.child, childi)
								childi.parent = child0.parent
								break __merge__
							} else {
								if len(child0.child) > 0 && len(childi.child) > 0 {
									child0 = child0.child[len(child0.child)-1]
									childi = childi.child[0]
								} else {
									break __merge__
								}
							}

						} else {
							break __merge__
						}
					}
				}
			} else {
				jtss[0][0].child = append(jtss[0][0].child, jtss[i][0])
			}
		}
		return jtss[0]
	}
	return nil
}

注:Assemble将4棵不同类型值的子树合并为一棵语法树。

语法树打印如下:

level:0,TokenCode:0X20000,TokenString:"putjsontest",JsonArrTokenCodeRoute:[],equity:[]
level:1,TokenCode:0X200000,TokenString:"aaab",JsonArrTokenCodeRoute:[],equity:[0xc000070230]
level:1,TokenCode:0X200000,TokenString:"fff",JsonArrTokenCodeRoute:[],equity:[0xc000070380]
level:1,TokenCode:0X40000,TokenString:"comboolarr",JsonArrTokenCodeRoute:[],equity:[]
level:2,TokenCode:0X40000,TokenString:"boolarr0",JsonArrTokenCodeRoute:[],equity:[]
level:3,TokenCode:0X1000000,TokenString:true,JsonArrTokenCodeRoute:[],equity:[]
level:3,TokenCode:0X2000000,TokenString:false,JsonArrTokenCodeRoute:[],equity:[]
level:2,TokenCode:0X40000,TokenString:"boolarr1",JsonArrTokenCodeRoute:[],equity:[]
level:3,TokenCode:0X1000000,TokenString:true,JsonArrTokenCodeRoute:[],equity:[]
level:3,TokenCode:0X2000000,TokenString:false,JsonArrTokenCodeRoute:[],equity:[]
level:1,TokenCode:0X20000,TokenString:"arrarrstrct",JsonArrTokenCodeRoute:[],equity:[]
level:2,TokenCode:0X10000,TokenString:"nnn",JsonArrTokenCodeRoute:[],equity:[0xc000070e00]
level:2,TokenCode:0X40000,TokenString:"ccc",JsonArrTokenCodeRoute:[],equity:[]
level:3,TokenCode:0X4,TokenString:0,JsonArrTokenCodeRoute:[],equity:[]
level:4,TokenCode:0X400000,TokenString:"sdf	sdfsfe29asdf",JsonArrTokenCodeRoute:[],equity:[]
level:4,TokenCode:0X400000,TokenString:"nmbndfvdfgfdg",JsonArrTokenCodeRoute:[],equity:[]
level:3,TokenCode:0X4,TokenString:1,JsonArrTokenCodeRoute:[],equity:[]
level:4,TokenCode:0X400000,TokenString:"sdf	sdfsfe29asdf",JsonArrTokenCodeRoute:[],equity:[]
level:4,TokenCode:0X400000,TokenString:"poiuiyyttt",JsonArrTokenCodeRoute:[],equity:[]
level:1,TokenCode:0X10000,TokenString:"aaa",JsonArrTokenCodeRoute:[],equity:[0xc000070f50]
level:1,TokenCode:0X20000,TokenString:"arrarrstrct",JsonArrTokenCodeRoute:[],equity:[]
level:2,TokenCode:0X40000,TokenString:"ccc",JsonArrTokenCodeRoute:[],equity:[]
level:3,TokenCode:0X4,TokenString:0,JsonArrTokenCodeRoute:[],equity:[]
level:4,TokenCode:0X400000,TokenString:"sdf	sdfsfe29asdf",JsonArrTokenCodeRoute:[],equity:[]
level:4,TokenCode:0X400000,TokenString:"nmbndfvdfgfdg",JsonArrTokenCodeRoute:[],equity:[]
level:3,TokenCode:0X4,TokenString:1,JsonArrTokenCodeRoute:[],equity:[]
level:4,TokenCode:0X400000,TokenString:"sdf	sdfsfe29asdf",JsonArrTokenCodeRoute:[],equity:[]
level:4,TokenCode:0X400000,TokenString:"poiuiyyttt",JsonArrTokenCodeRoute:[],equity:[]
level:1,TokenCode:0X10000,TokenString:"ddd",JsonArrTokenCodeRoute:[],equity:[0xc000071960]

(二)ToJson

type JsonTokenTree = *JsonToken

// results json (i64key for example): [{"key":23434}, "tn":{"filed0":"dfd","field1":435,"field2":true,"field3":[{...}]},{"key":345}, "tn":{"filed0":"dfdrtret","field1":45435,"field2":true,"field3":[{...}]}]
// when call ToJson, bstart and bend should be true
func (jtree JsonTokenTree) ToJson(bstart, bend bool, incs string) string {
	tmp := jtree
	switch tmp.jtt {
	case JsonObjField:
		incs = incs + tmp.jttstr + ":{"
	case JsonArrField:
		if tmp.parent.jtt == JsonArrField || tmp.parent.jtt == JsonArrStart {
			incs = incs + "{" + tmp.jttstr + ":["
		} else {
			incs = incs + tmp.jttstr + ":["
		}
	case JsonStrField, JsonNumField, JsonBoolField:
		incs = incs + tmp.jttstr + ":"
	case JsonArrStr, JsonArrNum, JsonArrFalse, JsonArrTrue:
		incs = incs + tmp.jttstr
	case JsonObjStart:
		incs = incs + "{"
	case JsonArrStart:
		incs = incs + "["
	}
	for i := 0; i < len(tmp.child); i++ {
		if i == 0 {
			if len(tmp.child) > 1 {
				incs = jtree.child[i].ToJson(true, false, incs)
			} else {
				incs = jtree.child[i].ToJson(true, true, incs)
			}
		} else if i == len(tmp.child)-1 {
			incs = jtree.child[i].ToJson(false, true, incs)
		} else {
			incs = jtree.child[i].ToJson(false, false, incs)
		}
	}
	switch tmp.jtt {
	case JsonObjField, JsonObjStart:
		if !bend {
			incs = incs + "},"
		} else {
			incs = incs + "}"
		}
	case JsonArrField:
		if tmp.parent.jtt == JsonArrField || tmp.parent.jtt == JsonArrStart {
			if !bend {
				incs = incs + "]},"
			} else {
				incs = incs + "]}"
			}
		} else {
			if !bend {
				incs = incs + "],"
			} else {
				incs = incs + "]"
			}
		}
	case JsonArrStart:
		if !bend {
			incs = incs + "],"
		} else {
			incs = incs + "]"
		}
	case JsonStrField, JsonNumField, JsonBoolField:
		if !bend {
			incs = incs + tmp.equity[0].jttstr + ","
		} else {
			incs = incs + tmp.equity[0].jttstr
		}
	case JsonArrStr, JsonArrNum, JsonArrFalse, JsonArrTrue:
		if !bend {
			incs = incs + ","
		}
	}
	return incs
}

序列化的字符串如下:

"putjsontest":{"aaab":true,"fff":false,"comboolarr":[{"boolarr0":[true,false]},{"boolarr1":[true,false]}],"arrarrstrct":{"nnn":-1234567890,"ccc":[["sdf	sdfsfe29asdf","nmbndfvdfgfdg"],["sdf	sdfsfe29asdf","poiuiyyttt"]]},"aaa":"sdf	sdfsfe29asdf","arrarrstrct":{"ccc":[["sdf	sdfsfe29asdf","nmbndfvdfgfdg"],["sdf	sdfsfe29asdf","poiuiyyttt"]]},"ddd":"sdf	sdfsfe29asdf"}

注:输出的json字符串为未封闭的,即未添加最外层{},方便进行其他处理。由于本次添加了PUTJSON标志,因此put被忽略。可以看出序列化出来的字符串符合预期,除去标志和未封边,与原json字符串一致。

你可能感兴趣的:(golang,b树,json)