导读:一个退役中校教你如何用go语言写一个基于B+树的json数据库(进阶篇)之json字符串解析为BsTr结构(一)-CSDN博客
// 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]}
// 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]
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字符串一致。