PB JSON工具n_json新版本

更新内容

新增方法

getKeys

获取属性名列表,返回属性个数

n_json ljson
string ls_key_list[]
long ll_key_count

ljson = create n_json
ljson.parse('{"itemCode":"0001","itemName":"PowerBuilder","sequence":1}')

//获取属性名列表
ll_key_count = ljson.getKeys(ls_key_list)

return 0

在这里插入图片描述

extend

将目标json的属性并入当前json

n_json ljson,ljson_other
string ls

ljson = create n_json
ljson.parse('{"itemCode":"0001","itemName":"PowerBuilder","sequence":1}')

ljson_other = create n_json
ljson_other.parse('{"itemClass":"Programming","status":"1"}')

//将目标json的属性并入当前json
ljson.extend(ljson_other)
ls = ljson.stringify()

return 0

在这里插入图片描述

setSQL、setSQLRow

将SQL检索出结果集后转json
测试表数据检索如下:
在这里插入图片描述

测试setSQL代码:

n_json ljson
string ls_sql,ls

ls_sql = "select employee_id emp_id, "+&
			"       first_name||' '||last_name emp_name, "+&
			"       decode(gender,'M','Male','F','Female','Unknown') gender, "+&
			"       email email "+&
			"  from tbl_employee "

ljson = create n_json
//设置SQL结果集
ljson.setSQL('employees',ls_sql)

ljson.pretty_stringify = true
ls = ljson.stringify()

return 0

测试SQL语句执行结果如下:
在这里插入图片描述
代码执行效果:
在这里插入图片描述
测试setSQLRow代码:

n_json ljson
string ls_sql,ls

ls_sql = "select first_name,last_name,gender,email from tbl_employee where employee_id = 1 "

ljson = create n_json
//设置SQL单行结果
ljson.setSQLRow(ls_sql,1)

ljson.pretty_stringify = true
ls = ljson.stringify()

return 0

测试SQL语句执行结果如下:
在这里插入图片描述
代码执行效果:
在这里插入图片描述

修改方法

hasItem

原方法名contains改为hasItem,判定属性当前json对象中是否存在

stringify

原方法名getFormat改为stringify,内部方法重写,提升效率

修改属性

pretty_stringify

原属性名pretty_print改为pretty_stringify,转字符串是否填充换行符、制表符

源代码

代码拷贝到文本编辑器,另存为 n_json.sru,导入pbl
发现BUG请留言或私信,以便修正(QQ:768310524 TEL:18649713925)

PB12.5版本

$PBExportHeader$n_json.sru
forward
global type n_json from nonvisualobject
end type
type st_item from structure within n_json
end type
type st_name_exp from structure within n_json
end type
type st_data_col from structure within n_json
end type
end forward

type st_item from structure
	string		name
	any		value
end type

type st_name_exp from structure
	string		name
	boolean		islist
	long		idx_begin
	long		idx_end
end type

type st_data_col from structure
	string		colname
	string		coltype
	string		attrname
end type

global type n_json from nonvisualobject
event readme ( )
end type
global n_json n_json

type variables
private:
	string items_idx='|' // |item1:1|item2:2|
	st_item item_list[]
	
	string jsonstr
	char jsonc[]
	long idx,jsonlen
	
public:
	string date_format = 'yyyy-mm-dd'
	string time_format = 'hh:mm:ss'
	string datetime_format = 'yyyy-mm-dd hh:mm:ss'
	string item_name_style = '' // STYLE_LOWER  STYLE_UPPER  STYLE_CAMEL  STYLE_PASCAL
	
	boolean pretty_stringify
	
	constant string STYLE_LOWER = 'STYLE_LOWER'
	constant string STYLE_UPPER = 'STYLE_UPPER'
	constant string STYLE_CAMEL = 'STYLE_CAMEL'
	constant string STYLE_PASCAL = 'STYLE_PASCAL'
	
end variables

forward prototypes
public subroutine reset ()
public function any getitem (string item_name)
public function integer delitem (string item_name)
public function integer setdata (string item_name, any data)
public function integer setdatarow (any data, long row)
public function integer setdatarow (string item_name, any data, long row)
private function integer _get_idx (string item_name)
private function string _trans_name (string item_name)
public function integer setdatarow (string item_name, any data, long begin_row, long end_row)
private subroutine _skip ()
private function integer _parse_list (ref any value[])
private function integer _parse_value (ref any value)
private subroutine _regenerate_items_idx ()
public function integer setitem (string item_name, any item_value)
public function long exportdatarow (any data)
public function long exportdata (string item_name, any data)
private function integer _parse_json (n_json ajson)
private function date _to_date (string s)
private function time _to_time (string s)
private function datetime _to_datetime (string s)
public function long getlistjson (string item_name, ref n_json rjson[])
public function any getitempath (string item_path)
private function integer _parse_expression (string expression, ref st_name_exp rst_name_exp)
public function any getitemexp (string item_expression)
public function integer rename (string item_name, string new_name)
private function integer _trans_list (ref any value[])
private function integer _trans_value (ref any value)
public function integer parse (string s)
private function boolean _check_spc (character c)
public function long getkeys (ref string keys[])
public function integer _get_data_col (any data, ref st_data_col data_col[])
private function integer _trans_data_row (any data, long row, st_data_col data_col[], ref st_item rst_item[])
public function integer extend (n_json ajson)
public function string stringify ()
public subroutine _stringify_json (n_json ajson, integer level)
public subroutine _stringify_list (n_json ajson, any value[], integer level)
public subroutine _stringify_value (n_json ajson, any value, integer level)
public subroutine _fill_jsonc (string s)
public function integer setsql (string item_name, string sql)
public function integer setsqlrow (string sql, long row)
public function boolean hasitem (string item_name)
public function integer setsqlrow (string item_name, string sql, long row)
public function integer setsqlrow (string item_name, string sql, long begin_row, long end_row)
public function long _sql_to_ds (string sql, ref datastore ds)
end prototypes

public subroutine reset ();st_item lst_items[]
char lc[]

item_list = lst_items
items_idx = '|'
jsonstr = ''
jsonc = lc
idx = 0
jsonlen = 0
end subroutine

public function any getitem (string item_name);any la_item_value
int i

setnull(la_item_value)
i = _get_idx(item_name)
if i > 0 then la_item_value = item_list[i].value

return la_item_value
end function

public function integer delitem (string item_name);int li_idx,i
st_item lst_items[]

li_idx = _get_idx(item_name)
if li_idx < 1 then return -1

for i = 1 to li_idx - 1
	lst_items[i] = item_list[i]
next
for i = li_idx + 1 to upperbound(item_list)
	lst_items[i - 1] = item_list[i]
next

item_list = lst_items
_regenerate_items_idx()

return 0
end function

public function integer setdata (string item_name, any data);return setdatarow(item_name,data,1,data.dynamic rowcount())
end function

public function integer setdatarow (any data, long row);long i
st_data_col lst_col[]
st_item lst_item[]

if _get_data_col(data,lst_col) < 0 then return -1
if  _trans_data_row(data,row,lst_col,lst_item) < 0 then return -1
for i = 1 to upperbound(lst_item)
	item_list[upperbound(item_list) + 1] = lst_item[i]
next
_regenerate_items_idx()

return 0

end function

public function integer setdatarow (string item_name, any data, long row);n_json ljson

ljson = create n_json
ljson.date_format = date_format
ljson.time_format = time_format
ljson.datetime_format = datetime_format
ljson.item_name_style = item_name_style
ljson.pretty_stringify = pretty_stringify
ljson.setdatarow(data,row)

return setitem(item_name,ljson)
end function

private function integer _get_idx (string item_name);long ll_pos1,ll_pos2

ll_pos1 = pos(items_idx,'|'+item_name+':')
if ll_pos1 < 1 then return -1

ll_pos1 += len(item_name) + 2
ll_pos2 = pos(items_idx,'|',ll_pos1+1)

return integer(mid(items_idx, ll_pos1, ll_pos2 - ll_pos1))

end function

private function string _trans_name (string item_name);string ls_name
char lc[],lc_name[]
long i,j
boolean lb_trans_flag

//命名规则转换
choose case item_name_style //user_name
	case STYLE_UPPER //USER_NAME
		ls_name = upper(item_name)
	case STYLE_LOWER //user_name
		ls_name = lower(item_name)
	case STYLE_CAMEL //userName
		lc = item_name
		for i = 1 to upperbound(lc)
			if lc[i] = '_' then 
				lb_trans_flag = true
				continue
			end if
			j ++
			if lb_trans_flag then
				lc_name[j] = upper(string(lc[i]))
				lb_trans_flag = false
			else
				lc_name[j] = lower(string(lc[i]))
			end if
		next
		ls_name = lc_name
	case STYLE_PASCAL //UserName
		lc = item_name
		lb_trans_flag = true
		for i = 1 to upperbound(lc)
			if lc[i] = '_' then 
				lb_trans_flag = true
				continue
			end if
			j ++
			if lb_trans_flag then
				lc_name[j] = upper(string(lc[i]))
				lb_trans_flag = false
			else
				lc_name[j] = lower(string(lc[i]))
			end if
		next
		ls_name = lc_name
	case else
		return item_name
end choose

return ls_name
end function

public function integer setdatarow (string item_name, any data, long begin_row, long end_row);long i,j
n_json ljson_list[]
st_data_col lst_col[]
st_item lst_item[],lst_null[]

if _get_data_col(data,lst_col) < 0 then return -1
for i = begin_row to end_row
	lst_item = lst_null
	if _trans_data_row(data,i,lst_col,lst_item) < 0 then return -1
	j += 1
	ljson_list[j] = create n_json
	ljson_list[j].date_format = date_format
	ljson_list[j].time_format = time_format
	ljson_list[j].datetime_format = datetime_format
	ljson_list[j].item_name_style = item_name_style
	ljson_list[j].pretty_stringify = pretty_stringify
	ljson_list[j].item_list = lst_item
	ljson_list[j]._regenerate_items_idx()
next

return setitem(item_name,ljson_list)

end function

private subroutine _skip ();char c

do 
   idx += 1
   c = jsonc[idx]
loop while _check_spc(c)

end subroutine

private function integer _parse_list (ref any value[]);long i
any la_list[],la_value_list[]

_skip()
do until jsonc[idx] = ']'
	i += 1
	if _parse_value(la_list[i]) < 0 then return -1
	
	_skip()
	if jsonc[idx] = ',' then _skip()
loop
value = la_list

return 0
end function

private function integer _parse_value (ref any value);string ls_value
n_json ljson
any la_value,la_list[]
long ll_pos
long i
char lc_value[]

choose case jsonc[idx]
	case '{'
		ljson = create n_json
		if _parse_json(ljson) < 0 then return -1
		la_value = ljson
	case '['
		if _parse_list(la_list) < 0 then return -1
		la_value = la_list
	case '"'
		idx += 1
		do until jsonc[idx] = '"' or idx > jsonlen
			if jsonc[idx] = '\' then 
				idx += 1
				if not (jsonc[idx] = '"' or jsonc[idx] = '\') then
					i ++
					choose case jsonc[idx]
						case 't'
							lc_value[i] = '~t'
						case 'r'
							lc_value[i] = '~r'
						case 'n'
							lc_value[i] = '~n'
						case 'f'
							lc_value[i] = '~f'
						case 'b'
							lc_value[i] = '~b'
						case 'u'
							lc_value[i] = '\'
							i ++
							lc_value[i] = jsonc[idx]
						case else
							return -1
					end choose
					idx += 1
					continue
				end if
			end if
			i ++
			lc_value[i] = jsonc[idx]
			idx += 1
		loop
		ls_value = lc_value
		la_value = ls_value
	case '0' to '9','+','-',&
		   't','f',&
		   'n'
		do until jsonc[idx] = ',' or jsonc[idx] = ']' or jsonc[idx] = '}' or _check_spc(jsonc[idx]) or idx > jsonlen
			i ++
			lc_value[i] = jsonc[idx]
			idx += 1
		loop
		ls_value = lc_value
		idx -= 1
		if isnumber(ls_value) then
			if pos(ls_value,'E') > 0 or pos(ls_value,'e') > 0 then
				la_value = double(ls_value)
			elseif pos(ls_value,'.') > 0 then
				la_value = dec(ls_value)
			else
				la_value = long(ls_value)
			end if
		else
			choose case ls_value
				case 'true'
					la_value = true
				case 'false'
					la_value = false
				case 'null'
					setnull(la_value)
				case else
					return -1
			end choose
		end if
	case else
		return -1
end choose
value = la_value

return 0
end function

private subroutine _regenerate_items_idx ();int i

items_idx = '|'
for i = 1 to upperbound(item_list)
	items_idx += item_list[i].name + ':' + string(i) + '|'
next

end subroutine

public function integer setitem (string item_name, any item_value);st_item lst_item
int li_idx
any la_item_value

_trans_value(item_value)
li_idx = _get_idx(item_name)

if li_idx < 0 then 
	lst_item.name = item_name
	lst_item.value = item_value
	li_idx = upperbound(item_list)+1
	item_list[li_idx] = lst_item
	items_idx += item_name+':'+string(li_idx)+'|'
else
	item_list[li_idx].value = item_value
end if

return li_idx
end function

public function long exportdatarow (any data);long ll_row
int i
string ls_colname,ls_coltype
string ls_item_name
any la_item_value
string ls_cls
string ls_value,ls_date,ls_time,ls_datetime

if upperbound(data) >= 0 then return -1
choose case data.dynamic typeof()
	case DataWindow!,DataStore!
	case else
		return -1
end choose

ll_row = data.dynamic insertrow(0)
for i = 1 to upperbound(item_list)
	ls_item_name = item_list[i].name
	la_item_value = item_list[i].value
	if upperbound(la_item_value) >= 0 then continue
	ls_colname = data.dynamic describe(ls_item_name+".name")
	if ls_colname = '!' or ls_colname = '?' or ls_colname = '' or isnull(ls_colname) then continue
	ls_coltype = data.dynamic describe(ls_item_name+".coltype")
	ls_cls = classname(la_item_value)
	choose case lower(mid(ls_coltype,1,4))
		case 'char'  //-->string
			if not (ls_cls = 'string') then continue
		case 'deci'/*decimal*/,'numb'/*number*/,'long','ulon'/*ulong*/,'real'
			if not (ls_cls = 'decimal' or & 
					  ls_cls = 'double' or &
					  ls_cls = 'integer' or &
					  ls_cls = 'long' or &
					  ls_cls = 'unsignedinteger' or &
					  ls_cls = 'unsignedlong' or &
					  ls_cls = 'real') then continue
		case 'date','time' // date datetime time
			if not (ls_cls = 'string') then continue
			ls_value = la_item_value
			if ls_coltype = 'date' then
				la_item_value = _to_date(ls_value)
			elseif ls_coltype = 'datetime' then
				la_item_value = _to_datetime(ls_value)
			elseif ls_coltype = 'time' then
				la_item_value = _to_time(ls_value)
			end if
		case else
			continue
	end choose
	data.dynamic setitem(ll_row,ls_item_name,la_item_value)
next

return ll_row
end function

public function long exportdata (string item_name, any data);any la_list[]
any la_value
long ll_count,i
n_json ljson
long ll_export

la_value = getitem(item_name)
ll_count = upperbound(la_value)
if ll_count < 0 then
	la_list[1] = la_value
	ll_count = 1
else
	la_list = la_value
end if

data.dynamic setredraw(false)
for i = 1 to ll_count
	yield()
	if not classname(la_list[i]) = classname(this) then continue
	ljson = la_list[i]
	ljson.exportdatarow(data)
	ll_export += 1
next
data.dynamic setredraw(true)

return ll_export

end function

private function integer _parse_json (n_json ajson);string ls_item_name
any la_value,la_list[]
char lc_name[],lc_empty[]
long i

_skip()
do while idx < jsonlen
	if jsonc[idx] = '}' then return 0
	if jsonc[idx] <> '"' then return -1
	ls_item_name = ''
	
	idx += 1
	i = 0
	lc_name = lc_empty
	do until jsonc[idx] = '"'
		i ++
		lc_name[i] = jsonc[idx]
		idx += 1
	loop
	ls_item_name = lc_name
	
	_skip()
	if jsonc[idx] <> ':' then return -1
	
	_skip()
	if _parse_value(la_value) < 0 then return -1
	
	ajson.setitem(ls_item_name,la_value)
	
	_skip()
	if jsonc[idx] = ',' then
		_skip()
	elseif jsonc[idx] = '}' then
		return 0
	end if
loop

return 0
end function

private function date _to_date (string s);date ld
string ls_year,ls_month,ls_day

setnull(ld)
if len(s) <> len(date_format) then return ld
ls_year = mid(s,pos(date_format,'yyyy'),4)
ls_month = mid(s,pos(date_format,'mm'),2)
ls_day = mid(s,pos(date_format,'dd'),2)
if not (isnumber(ls_year) and isnumber(ls_month) and isnumber(ls_day)) then return ld
ld = date(integer(ls_year),integer(ls_month),integer(ls_day))
if string(ld,date_format) <> s then setnull(ld)

return ld
end function

private function time _to_time (string s);time lt
string ls_hour,ls_minute,ls_second

setnull(lt)
if len(s) <> len(time_format) then return lt
ls_hour = mid(s,pos(time_format,'hh'),2)
ls_minute = mid(s,pos(time_format,'mm'),2)
ls_second = mid(s,pos(time_format,'ss'),2)
if not (isnumber(ls_hour) and isnumber(ls_minute) and isnumber(ls_second)) then return lt
lt = time(integer(ls_hour),integer(ls_minute),integer(ls_second))
if string(lt,time_format) <> s then setnull(lt)

return lt
end function

private function datetime _to_datetime (string s);datetime ldt
date ld
time lt
string ls_year,ls_month,ls_day
string ls_hour,ls_minute,ls_second

setnull(ldt)
if len(s) <> len(datetime_format) then return ldt
ls_year = mid(s,pos(date_format,'yyyy'),4)
ls_month = mid(s,pos(date_format,'mm'),2)
ls_day = mid(s,pos(date_format,'dd'),2)
ls_hour = mid(s,pos(time_format,'hh'),2)
ls_minute = mid(s,lastpos(time_format,'mm'),2)
ls_second = mid(s,pos(time_format,'ss'),2)

if not (isnumber(ls_year) and isnumber(ls_month) and isnumber(ls_day) and isnumber(ls_hour) and isnumber(ls_minute) and isnumber(ls_second)) then return ldt
ld = date(integer(ls_year),integer(ls_month),integer(ls_day))
lt = time(integer(ls_hour),integer(ls_minute),integer(ls_second))
ldt = datetime(ld,lt)
if string(ldt,datetime_format) <> s then setnull(ldt)

return ldt
end function

public function long getlistjson (string item_name, ref n_json rjson[]);any la_value,la_list[]
n_json ljson[]
long i

la_value = getitem(item_name)
if upperbound(la_value) < 0 then return -1

la_list = la_value
for i = 1 to upperbound(la_list)
	if upperbound(la_list[i]) >= 0 then return -1
	if isnull(la_list[i]) then return -1
	if classname(la_list[i]) <> classname(this) then return -1
next

rjson = la_list
return upperbound(rjson)
end function

public function any getitempath (string item_path);any la,la_value,la_list_get[],la_list_set[]
n_json ljson_value
long i,ll_len
char lc[]
string ls_item_expression,ls_next_path

lc =item_path
ll_len = upperbound(lc)
if ll_len <= 0 then return la

i = 1
if lc[i] <> '/' then return la

i += 1
do until lc[i] = '/'
	ls_item_expression = ls_item_expression + lc[i]
	i += 1
	if i > ll_len then exit
loop

la_value = getitemexp(ls_item_expression)
if i > ll_len then return la_value
ls_next_path = mid(item_path,i)

if upperbound(la_value) >= 0 then
	la_list_get = la_value
	for i = 1 to upperbound(la_list_get)
		if classname(la_list_get[i]) = classname(this) then
			ljson_value = la_list_get[i]
			la_list_set[i] = ljson_value.getitempath(ls_next_path)
		else
			la_list_set[i] = la
		end if
	next
	return la_list_set
else
	if classname(la_value) = classname(this) then
		ljson_value = la_value
		return ljson_value.getitempath(ls_next_path)
	else
		return la
	end if
end if

return la
end function

private function integer _parse_expression (string expression, ref st_name_exp rst_name_exp);char lc[]
string ls_item_name,ls_idx_begin,ls_idx_end
long ll_idx_begin,ll_idx_end
long i = 1
if not match(expression,'.+\[.+\]$') then return -1
lc = expression
do until lc[i] = '['
	ls_item_name = ls_item_name + lc[i]
	i += 1
loop

i += 1
do until lc[i] = ':' or lc[i] = ']'
	ls_idx_begin = ls_idx_begin + lc[i]
	i += 1
loop
if ls_idx_begin = '' then ls_idx_begin = '1'
if not isnumber(ls_idx_begin) then return -1
ll_idx_begin = long(ls_idx_begin)
if lc[i] = ':' then
	i += 1
	do until lc[i] = ']'
		ls_idx_end = ls_idx_end + lc[i]
		i += 1
	loop
	if ls_idx_end = '' then ls_idx_end = '0'
	if not isnumber(ls_idx_end) then return -1
	ll_idx_end = long(ls_idx_end)
	if ll_idx_end > 0 and ll_idx_end < ll_idx_begin then return -1
	rst_name_exp.islist = true
else
	ll_idx_end = ll_idx_begin
	rst_name_exp.islist = false
end if

rst_name_exp.name = ls_item_name
rst_name_exp.idx_begin = ll_idx_begin
rst_name_exp.idx_end = ll_idx_end
return 0
end function

public function any getitemexp (string item_expression);any la_value,la_item_value
any la_list_get[],la_list_set[]
long i
st_name_exp lst_name_exp

setnull(la_item_value)
if _parse_expression(item_expression,lst_name_exp) < 0 then return getitem(item_expression)

la_value = getitem(lst_name_exp.name)
if isnull(la_value) then return la_item_value
if upperbound(la_value) < max(lst_name_exp.idx_begin,lst_name_exp.idx_end) then return la_item_value
la_list_get = la_value
if lst_name_exp.isList then
	if lst_name_exp.idx_end = 0 then lst_name_exp.idx_end = upperbound(la_list_get)
	for i = 1 to lst_name_exp.idx_end - lst_name_exp.idx_begin + 1
		la_list_set[i] = la_list_get[lst_name_exp.idx_begin + i - 1]
	next
	la_item_value = la_list_set
else
	la_item_value = la_list_get[lst_name_exp.idx_begin]
end if
	
return la_item_value
end function

public function integer rename (string item_name, string new_name);int li_idx

li_idx = _get_idx(item_name)
if li_idx < 0 then return -1

item_list[li_idx].name = new_name
_regenerate_items_idx()

return li_idx
end function

private function integer _trans_list (ref any value[]);long i

for i = 1 to upperbound(value)
	_trans_value(value[i])
next

return 0
end function

private function integer _trans_value (ref any value);any la_value

if upperbound(value) >= 0 then 
	_trans_list(value)
	return 0
end if

if isnull(value) then return 0
choose case classname(value)
	case classname(this)
		la_value = value
	case 'string'
		la_value = value
	case 'integer','unsignedinteger','long','unsignedlong','decimal','double','real'
		la_value = value
	case 'boolean'
		la_value = value
	case 'date'
		la_value = string(value,date_format)
	case 'time'
		la_value = string(value,time_format)
	case 'datetime' 
		la_value = string(value,datetime_format)
	case else
		setnull(la_value)
end choose

value = la_value
return 0
end function

public function integer parse (string s);reset()
jsonstr = s
jsonc = s
jsonlen = upperbound(jsonc)

_skip()
if jsonc[idx] <> '{' then return -1
if _parse_json(this) < 0 then return -1

return 0
end function

private function boolean _check_spc (character c);
if c=' ' or c='~r' or c='~n' or c='~t' or c='~b' or c='~f' then return true
return false
end function

public function long getkeys (ref string keys[]);long i
string ls_keys[]

for i = 1 to upperbound(item_list)
	ls_keys[i] = item_list[i].name
next

keys = ls_keys
return upperbound(keys)
end function

public function integer _get_data_col (any data, ref st_data_col data_col[]);
int li_colcount
long i,j,p1,p2
string ls_tag,ls_attr_name
any la_value

if upperbound(data) >= 0 then return -1
choose case data.dynamic typeof()
	case DataWindow!,DataStore!
	case else
		return -1
end choose

li_colcount = integer(data.dynamic describe("datawindow.column.count"))
for i = 1 to li_colcount
	ls_tag = data.dynamic describe("#"+string(i)+".tag")
	p1 = pos(ls_tag,'@attr(')
	if p1 > 0 then
		p1 += 6
		p2 = pos(ls_tag,')',p1)
		ls_attr_name = mid(ls_tag,p1,p2 - p1)
		if ls_attr_name = 'null' then continue
	else
		ls_attr_name = ''
	end if
	j += 1
	data_col[j].colname = data.dynamic describe("#"+string(i)+".name")
	data_col[j].coltype = data.dynamic describe("#"+string(i)+'.coltype')
	if isnull(ls_attr_name) or ls_attr_name='' then ls_attr_name = data_col[j].colname
	data_col[j].attrname = ls_attr_name
next


return 0
end function

private function integer _trans_data_row (any data, long row, st_data_col data_col[], ref st_item rst_item[]);
long i,ll_rowcount
any la_value

ll_rowcount = data.dynamic rowcount()
if row > ll_rowcount then return -1

for i = 1 to upperbound(data_col)
	choose case lower(left(data_col[i].coltype,4))
		case 'char'	//string
			la_value = data.dynamic getitemstring(row,data_col[i].colname)
			if isnull(la_value) then la_value = ''
		case 'deci'/*decimal*/
			la_value = data.dynamic getitemdecimal(row,data_col[i].colname)
		case 'numb'/*number*/,'long','ulon'/*ulong*/,'real'
			la_value = data.dynamic getitemnumber(row,data_col[i].colname)
		case 'date'
			if data_col[i].coltype = 'date' then
				la_value = string(data.dynamic getitemdate(row,data_col[i].colname),date_format)
			else //datetime
				la_value = string(data.dynamic getitemdatetime(row,data_col[i].colname),datetime_format)
			end if
			if isnull(la_value) then la_value = ''
		case 'time'
			la_value = string(data.dynamic getitemtime(row,data_col[i].colname),time_format)
			if isnull(la_value) then la_value = ''
		case else
			setnull(la_value)
	end choose
	rst_item[i].name = data_col[i].attrname
	rst_item[i].value = la_value
next

return upperbound(rst_item)
end function

public function integer extend (n_json ajson);
st_item extend_list[]
int li_idx
int i

extend_list = ajson.item_list
for i = 1 to upperbound(extend_list)
	li_idx = _get_idx(extend_list[i].name)

	if li_idx < 0 then 
		li_idx = upperbound(item_list)+1
		item_list[li_idx] = extend_list[i]
		items_idx += extend_list[i].name+':'+string(li_idx)+'|'
	else
		item_list[li_idx].value = extend_list[i].value
	end if
next

return 0
end function

public function string stringify ();char lc_empty[]

idx = 0
jsonc = lc_empty

_stringify_json(this,1)

return jsonc
end function

public subroutine _stringify_json (n_json ajson, integer level);int i
string ls_tab

ajson._fill_jsonc('{')

if pretty_stringify then ls_tab = fill('~t',level - 1)

for i = 1 to upperbound(item_list)
	if pretty_stringify then
		ajson._fill_jsonc('~r~n~t')
		ajson._fill_jsonc(ls_tab)
	end if
	
	ajson._fill_jsonc('"')
	ajson._fill_jsonc(_trans_name(item_list[i].name))
	ajson._fill_jsonc('":')
	
	_stringify_value(ajson,item_list[i].value,level)
	
	if i < upperbound(item_list) then
		ajson._fill_jsonc(',')
	end if
next

if pretty_stringify then
	ajson._fill_jsonc('~r~n')
	ajson._fill_jsonc(ls_tab)
end if

ajson._fill_jsonc('}')

return
end subroutine

public subroutine _stringify_list (n_json ajson, any value[], integer level);long i

ajson._fill_jsonc('[')

for i = 1 to upperbound(value)
	_stringify_value(ajson,value[i],level)
	if i < upperbound(value) then
		ajson._fill_jsonc(',')
	end if
next

ajson._fill_jsonc(']')

return



end subroutine

public subroutine _stringify_value (n_json ajson, any value, integer level);string ls_value
n_json ljson
char lc_tmp[]
long i

if upperbound(value) >= 0 then
	_stringify_list(ajson,value,level)
elseif classname(value) = classname(this) then
	ljson = value
	ljson.item_name_style = item_name_style
	ljson.pretty_stringify = pretty_stringify
	ljson._stringify_json(ajson,level + 1)
else
	if isnull(classname(value)) then
		ajson._fill_jsonc('null')
	else
		choose case classname(value)
			case 'string'
				ajson._fill_jsonc('"')
				lc_tmp = string(value)
				for i = 1 to upperbound(lc_tmp)
					choose case lc_tmp[i]
						case '\'
							ajson._fill_jsonc('\')
							if lc_tmp[i + 1] = 'u' then continue
							ajson._fill_jsonc('\')
						case '"'
							ajson._fill_jsonc('\' + lc_tmp[i])
						case '~r'
							ajson._fill_jsonc('\r')
						case '~n'
							ajson._fill_jsonc('\n')
						case '~t'
							ajson._fill_jsonc('\t')
						case '~f'
							ajson._fill_jsonc('\f')
						case '~b'
							ajson._fill_jsonc('\b')
						case else
							ajson._fill_jsonc(lc_tmp[i])
					end choose
				next
				ajson._fill_jsonc('"')
			case else
				ajson._fill_jsonc(string(value))
		end choose
	end if
end if

return 

end subroutine

public subroutine _fill_jsonc (string s);char lc[]
long i

lc = s
for i = 1 to upperbound(lc)
	idx ++
	jsonc[idx] = lc[i]
next
end subroutine

public function integer setsql (string item_name, string sql);datastore lds_data

if _sql_to_ds(sql,lds_data) < 0 then return -1

return setdata(item_name,lds_data)
end function

public function integer setsqlrow (string sql, long row);datastore lds_data

if _sql_to_ds(sql,lds_data) < row then return -1

return setdatarow(lds_data,row)
end function

public function boolean hasitem (string item_name);return _get_idx(item_name) > 0
end function

public function integer setsqlrow (string item_name, string sql, long row);datastore lds_data

if _sql_to_ds(sql,lds_data) < row then return -1

return setdatarow(item_name,lds_data,row)
end function

public function integer setsqlrow (string item_name, string sql, long begin_row, long end_row);datastore lds_data

if _sql_to_ds(sql,lds_data) < end_row then return -1

return setdatarow(item_name,lds_data,begin_row,end_row)
end function

public function long _sql_to_ds (string sql, ref datastore ds);string ls_syntax
string ls_err

ls_syntax = SQLCA.SyntaxFromSQL(sql,'Style(Type=Grid)',ls_err)
if len(ls_err) > 0 then return -1

ds = create datastore
ds.create(ls_syntax,ls_err)
if len(ls_err) > 0 then return -1

ds.settransobject(SQLCA)
ds.retrieve()

return ds.rowcount()
end function

on n_json.create
call super::create
TriggerEvent( this, "constructor" )
end on

on n_json.destroy
TriggerEvent( this, "destructor" )
call super::destroy
end on

PB8、PB9版本

更新日志:


功能改进:
数据窗内容输入JSON,数据窗口列属性为隐藏时则不输入,修改_get_data_col。
JSON内容输入数据窗口,字符串类型可以自动转换为数字类型,修改exportdatarow,增加_to_number。

bug修复:
最后一个字符等于\时数组越界,修改_stringify_value。
防止汉字GBK编码后半部分包含\等特殊符号,修改_stringify_value、_parse_value。

mxl 20200329


$PBExportHeader$n_json.sru
forward
global type n_json from nonvisualobject
end type
type st_item from structure within n_json
end type
type st_name_exp from structure within n_json
end type
type st_data_col from structure within n_json
end type
end forward

type st_item from structure
	string		name
	any		value
end type

type st_name_exp from structure
	string		name
	boolean		islist
	long		idx_begin
	long		idx_end
end type

type st_data_col from structure
	string		colname
	string		coltype
	string		attrname
end type

global type n_json from nonvisualobject
event readme ( )
end type
global n_json n_json

type variables
private:
	string items_idx='|' // |item1:1|item2:2|
	st_item item_list[]
	
	string jsonstr
	char jsonc[]
	long idx,jsonlen
	
public:
	string date_format = 'yyyy-mm-dd'
	string time_format = 'hh:mm:ss'
	string datetime_format = 'yyyy-mm-dd hh:mm:ss'
	string item_name_style = '' // STYLE_LOWER  STYLE_UPPER  STYLE_CAMEL  STYLE_PASCAL
	
	boolean pretty_stringify
	
	constant string STYLE_LOWER = 'STYLE_LOWER'
	constant string STYLE_UPPER = 'STYLE_UPPER'
	constant string STYLE_CAMEL = 'STYLE_CAMEL'
	constant string STYLE_PASCAL = 'STYLE_PASCAL'
	
end variables

forward prototypes
public subroutine reset ()
public function any getitem (string item_name)
public function integer delitem (string item_name)
public function integer setdata (string item_name, any data)
public function integer setdatarow (any data, long row)
public function integer setdatarow (string item_name, any data, long row)
private function integer _get_idx (string item_name)
private function string _trans_name (string item_name)
public function integer setdatarow (string item_name, any data, long begin_row, long end_row)
private subroutine _skip ()
private function integer _parse_list (ref any value[])
private function integer _parse_value (ref any value)
private subroutine _regenerate_items_idx ()
public function integer setitem (string item_name, any item_value)
public function long exportdatarow (any data)
public function long exportdata (string item_name, any data)
private function integer _parse_json (n_json ajson)
private function date _to_date (string s)
private function time _to_time (string s)
private function datetime _to_datetime (string s)
public function long getlistjson (string item_name, ref n_json rjson[])
public function any getitempath (string item_path)
private function integer _parse_expression (string expression, ref st_name_exp rst_name_exp)
public function any getitemexp (string item_expression)
public function integer rename (string item_name, string new_name)
private function integer _trans_list (ref any value[])
private function integer _trans_value (ref any value)
public function integer parse (string s)
private function boolean _check_spc (character c)
public function long getkeys (ref string keys[])
public function integer _get_data_col (any data, ref st_data_col data_col[])
private function integer _trans_data_row (any data, long row, st_data_col data_col[], ref st_item rst_item[])
public function integer extend (n_json ajson)
public function string stringify ()
public subroutine _stringify_json (n_json ajson, integer level)
public subroutine _stringify_list (n_json ajson, any value[], integer level)
public subroutine _stringify_value (n_json ajson, any value, integer level)
public subroutine _fill_jsonc (string s)
public function integer setsql (string item_name, string sql)
public function integer setsqlrow (string sql, long row)
public function boolean hasitem (string item_name)
public function integer setsqlrow (string item_name, string sql, long row)
public function integer setsqlrow (string item_name, string sql, long begin_row, long end_row)
public function long _sql_to_ds (string sql, ref datastore ds)
private function decimal _to_number (string s)
end prototypes

public subroutine reset ();st_item lst_items[]
char lc[]

item_list = lst_items
items_idx = '|'
jsonstr = ''
jsonc = lc
idx = 0
jsonlen = 0
end subroutine

public function any getitem (string item_name);any la_item_value
int i

setnull(la_item_value)
i = _get_idx(item_name)
if i > 0 then la_item_value = item_list[i].value

return la_item_value
end function

public function integer delitem (string item_name);int li_idx,i
st_item lst_items[]

li_idx = _get_idx(item_name)
if li_idx < 1 then return -1

for i = 1 to li_idx - 1
	lst_items[i] = item_list[i]
next
for i = li_idx + 1 to upperbound(item_list)
	lst_items[i - 1] = item_list[i]
next

item_list = lst_items
_regenerate_items_idx()

return 0
end function

public function integer setdata (string item_name, any data);return setdatarow(item_name,data,1,data.dynamic rowcount())
end function

public function integer setdatarow (any data, long row);long i
st_data_col lst_col[]
st_item lst_item[]

if _get_data_col(data,lst_col) < 0 then return -1
if  _trans_data_row(data,row,lst_col,lst_item) < 0 then return -1
for i = 1 to upperbound(lst_item)
	item_list[upperbound(item_list) + 1] = lst_item[i]
next
_regenerate_items_idx()

return 0

end function

public function integer setdatarow (string item_name, any data, long row);n_json ljson

ljson = create n_json
ljson.date_format = date_format
ljson.time_format = time_format
ljson.datetime_format = datetime_format
ljson.item_name_style = item_name_style
ljson.pretty_stringify = pretty_stringify
ljson.setdatarow(data,row)

return setitem(item_name,ljson)
end function

private function integer _get_idx (string item_name);long ll_pos1,ll_pos2

ll_pos1 = pos(items_idx,'|'+item_name+':')
if ll_pos1 < 1 then return -1

ll_pos1 += len(item_name) + 2
ll_pos2 = pos(items_idx,'|',ll_pos1+1)

return integer(mid(items_idx, ll_pos1, ll_pos2 - ll_pos1))

end function

private function string _trans_name (string item_name);string ls_name
char lc[],lc_name[]
long i,j
boolean lb_trans_flag

//命名规则转换
choose case item_name_style //user_name
	case STYLE_UPPER //USER_NAME
		ls_name = upper(item_name)
	case STYLE_LOWER //user_name
		ls_name = lower(item_name)
	case STYLE_CAMEL //userName
		lc = item_name
		for i = 1 to upperbound(lc)
			if lc[i] = '_' then 
				lb_trans_flag = true
				continue
			end if
			j ++
			if lb_trans_flag then
				lc_name[j] = upper(string(lc[i]))
				lb_trans_flag = false
			else
				lc_name[j] = lower(string(lc[i]))
			end if
		next
		ls_name = lc_name
	case STYLE_PASCAL //UserName
		lc = item_name
		lb_trans_flag = true
		for i = 1 to upperbound(lc)
			if lc[i] = '_' then 
				lb_trans_flag = true
				continue
			end if
			j ++
			if lb_trans_flag then
				lc_name[j] = upper(string(lc[i]))
				lb_trans_flag = false
			else
				lc_name[j] = lower(string(lc[i]))
			end if
		next
		ls_name = lc_name
	case else
		return item_name
end choose

return ls_name
end function

public function integer setdatarow (string item_name, any data, long begin_row, long end_row);long i,j
n_json ljson_list[]
st_data_col lst_col[]
st_item lst_item[],lst_null[]

if _get_data_col(data,lst_col) < 0 then return -1
for i = begin_row to end_row
	lst_item = lst_null
	if _trans_data_row(data,i,lst_col,lst_item) < 0 then return -1
	j += 1
	ljson_list[j] = create n_json
	ljson_list[j].date_format = date_format
	ljson_list[j].time_format = time_format
	ljson_list[j].datetime_format = datetime_format
	ljson_list[j].item_name_style = item_name_style
	ljson_list[j].pretty_stringify = pretty_stringify
	ljson_list[j].item_list = lst_item
	ljson_list[j]._regenerate_items_idx()
next

return setitem(item_name,ljson_list)

end function

private subroutine _skip ();char c

do 
   idx += 1
   c = jsonc[idx]
loop while _check_spc(c)

end subroutine

private function integer _parse_list (ref any value[]);long i
any la_list[],la_value_list[]

_skip()
do until jsonc[idx] = ']'
	i += 1
	if _parse_value(la_list[i]) < 0 then return -1
	
	_skip()
	if jsonc[idx] = ',' then _skip()
loop
value = la_list

return 0
end function

private function integer _parse_value (ref any value);string ls_value
n_json ljson
any la_value,la_list[]
long ll_pos
long i
char lc_value[]

choose case jsonc[idx]
	case '{'
		ljson = create n_json
		if _parse_json(ljson) < 0 then return -1
		la_value = ljson
	case '['
		if _parse_list(la_list) < 0 then return -1
		la_value = la_list
	case '"'
		idx += 1
		do until jsonc[idx] = '"' or idx > jsonlen
			if asc(jsonc[idx]) > 127 then
				//防止汉字GBK编码后半部分包含\等特殊符号 MXL 20200326
				i ++
				lc_value[i] = jsonc[idx]
				i ++
				lc_value[i] = jsonc[idx + 1]
				idx += 2
				continue
			end if
			if jsonc[idx] = '\' then 
				idx += 1
				if not (jsonc[idx] = '"' or jsonc[idx] = '\') then
					i ++
					choose case jsonc[idx]
						case 't'
							lc_value[i] = '~t'
						case 'r'
							lc_value[i] = '~r'
						case 'n'
							lc_value[i] = '~n'
						case 'f'
							lc_value[i] = '~f'
						case 'b'
							lc_value[i] = '~b'
						case 'u'
							lc_value[i] = '\'
							i ++
							lc_value[i] = jsonc[idx]
						case else
							return -1
					end choose
					idx += 1
					continue
				end if
			end if
			i ++
			lc_value[i] = jsonc[idx]
			idx += 1
		loop
		ls_value = lc_value
		la_value = ls_value
	case '0' to '9','+','-',&
		   't','f',&
		   'n'
		do until jsonc[idx] = ',' or jsonc[idx] = ']' or jsonc[idx] = '}' or _check_spc(jsonc[idx]) or idx > jsonlen
			i ++
			lc_value[i] = jsonc[idx]
			idx += 1
		loop
		ls_value = lc_value
		idx -= 1
		if isnumber(ls_value) then
			if pos(ls_value,'E') > 0 or pos(ls_value,'e') > 0 then
				la_value = double(ls_value)
			elseif pos(ls_value,'.') > 0 then
				la_value = dec(ls_value)
			else
				la_value = long(ls_value)
			end if
		else
			choose case ls_value
				case 'true'
					la_value = true
				case 'false'
					la_value = false
				case 'null'
					setnull(la_value)
				case else
					return -1
			end choose
		end if
	case else
		return -1
end choose
value = la_value

return 0
end function

private subroutine _regenerate_items_idx ();int i

items_idx = '|'
for i = 1 to upperbound(item_list)
	items_idx += item_list[i].name + ':' + string(i) + '|'
next

end subroutine

public function integer setitem (string item_name, any item_value);st_item lst_item
int li_idx
any la_item_value

_trans_value(item_value)
li_idx = _get_idx(item_name)

if li_idx < 0 then 
	lst_item.name = item_name
	lst_item.value = item_value
	li_idx = upperbound(item_list)+1
	item_list[li_idx] = lst_item
	items_idx += item_name+':'+string(li_idx)+'|'
else
	item_list[li_idx].value = item_value
end if

return li_idx
end function

public function long exportdatarow (any data);long ll_row
int i
string ls_colname,ls_coltype
string ls_item_name
any la_item_value
string ls_cls
string ls_value,ls_date,ls_time,ls_datetime

if upperbound(data) >= 0 then return -1
choose case data.dynamic typeof()
	case DataWindow!,DataStore!
	case else
		return -1
end choose

ll_row = data.dynamic insertrow(0)
for i = 1 to upperbound(item_list)
	ls_item_name = item_list[i].name
	la_item_value = item_list[i].value
	if upperbound(la_item_value) >= 0 then continue
	ls_colname = data.dynamic describe(ls_item_name+".name")
	if ls_colname = '!' or ls_colname = '?' or ls_colname = '' or isnull(ls_colname) then continue
	ls_coltype = data.dynamic describe(ls_item_name+".coltype")
	ls_cls = classname(la_item_value)
	choose case lower(mid(ls_coltype,1,4))
		case 'char'  //-->string
			if not (ls_cls = 'string') then continue
		case 'deci'/*decimal*/,'numb'/*number*/,'long','ulon'/*ulong*/,'real'
			if not (ls_cls = 'string' or & 
					  ls_cls = 'decimal' or & 
					  ls_cls = 'double' or &
					  ls_cls = 'integer' or &
					  ls_cls = 'long' or &
					  ls_cls = 'unsignedinteger' or &
					  ls_cls = 'unsignedlong' or &
					  ls_cls = 'real') then continue
			if ls_cls = 'string' then //自动类型转换 尝试将字符串转换成数字 mxl 20200326
				ls_value = la_item_value
				la_item_value = _to_number(ls_value)
			end if
		case 'date','time' // date datetime time
			if not (ls_cls = 'string') then continue
			ls_value = la_item_value
			if ls_coltype = 'date' then
				la_item_value = _to_date(ls_value)
			elseif ls_coltype = 'datetime' then
				la_item_value = _to_datetime(ls_value)
			elseif ls_coltype = 'time' then
				la_item_value = _to_time(ls_value)
			end if
		case else
			continue
	end choose
	data.dynamic setitem(ll_row,ls_item_name,la_item_value)
next

return ll_row
end function

public function long exportdata (string item_name, any data);any la_list[]
any la_value
long ll_count,i
n_json ljson
long ll_export

la_value = getitem(item_name)
ll_count = upperbound(la_value)
if ll_count < 0 then
	la_list[1] = la_value
	ll_count = 1
else
	la_list = la_value
end if

data.dynamic setredraw(false)
for i = 1 to ll_count
	yield()
	if not classname(la_list[i]) = classname(this) then continue
	ljson = la_list[i]
	ljson.exportdatarow(data)
	ll_export += 1
next
data.dynamic setredraw(true)

return ll_export

end function

private function integer _parse_json (n_json ajson);string ls_item_name
any la_value,la_list[]
char lc_name[],lc_empty[]
long i

_skip()
do while idx < jsonlen
	if jsonc[idx] = '}' then return 0
	if jsonc[idx] <> '"' then return -1
	ls_item_name = ''
	
	idx += 1
	i = 0
	lc_name = lc_empty
	do until jsonc[idx] = '"'
		i ++
		lc_name[i] = jsonc[idx]
		idx += 1
	loop
	ls_item_name = lc_name
	
	_skip()
	if jsonc[idx] <> ':' then return -1
	
	_skip()
	if _parse_value(la_value) < 0 then return -1
	
	ajson.setitem(ls_item_name,la_value)
	
	_skip()
	if jsonc[idx] = ',' then
		_skip()
	elseif jsonc[idx] = '}' then
		return 0
	end if
loop

return 0
end function

private function date _to_date (string s);date ld
string ls_year,ls_month,ls_day

setnull(ld)
if len(s) <> len(date_format) then return ld
ls_year = mid(s,pos(date_format,'yyyy'),4)
ls_month = mid(s,pos(date_format,'mm'),2)
ls_day = mid(s,pos(date_format,'dd'),2)
if not (isnumber(ls_year) and isnumber(ls_month) and isnumber(ls_day)) then return ld
ld = date(integer(ls_year),integer(ls_month),integer(ls_day))
if string(ld,date_format) <> s then setnull(ld)

return ld
end function

private function time _to_time (string s);time lt
string ls_hour,ls_minute,ls_second

setnull(lt)
if len(s) <> len(time_format) then return lt
ls_hour = mid(s,pos(time_format,'hh'),2)
ls_minute = mid(s,pos(time_format,'mm'),2)
ls_second = mid(s,pos(time_format,'ss'),2)
if not (isnumber(ls_hour) and isnumber(ls_minute) and isnumber(ls_second)) then return lt
lt = time(integer(ls_hour),integer(ls_minute),integer(ls_second))
if string(lt,time_format) <> s then setnull(lt)

return lt
end function

private function datetime _to_datetime (string s);datetime ldt
date ld
time lt
string ls_year,ls_month,ls_day
string ls_hour,ls_minute,ls_second

setnull(ldt)
if len(s) <> len(datetime_format) then return ldt
ls_year = mid(s,pos(date_format,'yyyy'),4)
ls_month = mid(s,pos(date_format,'mm'),2)
ls_day = mid(s,pos(date_format,'dd'),2)
ls_hour = mid(s,pos(time_format,'hh'),2)
ls_minute = mid(s,lastpos(time_format,'mm'),2)
ls_second = mid(s,pos(time_format,'ss'),2)

if not (isnumber(ls_year) and isnumber(ls_month) and isnumber(ls_day) and isnumber(ls_hour) and isnumber(ls_minute) and isnumber(ls_second)) then return ldt
ld = date(integer(ls_year),integer(ls_month),integer(ls_day))
lt = time(integer(ls_hour),integer(ls_minute),integer(ls_second))
ldt = datetime(ld,lt)
if string(ldt,datetime_format) <> s then setnull(ldt)

return ldt
end function

public function long getlistjson (string item_name, ref n_json rjson[]);any la_value,la_list[]
long i

la_value = getitem(item_name)
if upperbound(la_value) < 0 then return -1

la_list = la_value
for i = 1 to upperbound(la_list)
	if upperbound(la_list[i]) >= 0 then return -1
	if isnull(la_list[i]) then return -1
	if classname(la_list[i]) <> classname(this) then return -1
	rjson[i] = la_list[i]
next

//rjson = la_list
return upperbound(rjson[])
end function

public function any getitempath (string item_path);any la,la_value,la_list_get[],la_list_set[]
n_json ljson_value
long i,ll_len
char lc[]
string ls_item_expression,ls_next_path

lc =item_path
ll_len = upperbound(lc)
if ll_len <= 0 then return la

i = 1
if lc[i] <> '/' then return la

i += 1
do until lc[i] = '/'
	ls_item_expression = ls_item_expression + lc[i]
	i += 1
	if i > ll_len then exit
loop

la_value = getitemexp(ls_item_expression)
if i > ll_len then return la_value
ls_next_path = mid(item_path,i)

if upperbound(la_value) >= 0 then
	la_list_get = la_value
	for i = 1 to upperbound(la_list_get)
		if classname(la_list_get[i]) = classname(this) then
			ljson_value = la_list_get[i]
			la_list_set[i] = ljson_value.getitempath(ls_next_path)
		else
			la_list_set[i] = la
		end if
	next
	return la_list_set
else
	if classname(la_value) = classname(this) then
		ljson_value = la_value
		return ljson_value.getitempath(ls_next_path)
	else
		return la
	end if
end if

return la
end function

private function integer _parse_expression (string expression, ref st_name_exp rst_name_exp);char lc[]
string ls_item_name,ls_idx_begin,ls_idx_end
long ll_idx_begin,ll_idx_end
long i = 1
if not match(expression,'.+\[.+\]$') then return -1
lc = expression
do until lc[i] = '['
	ls_item_name = ls_item_name + lc[i]
	i += 1
loop

i += 1
do until lc[i] = ':' or lc[i] = ']'
	ls_idx_begin = ls_idx_begin + lc[i]
	i += 1
loop
if ls_idx_begin = '' then ls_idx_begin = '1'
if not isnumber(ls_idx_begin) then return -1
ll_idx_begin = long(ls_idx_begin)
if lc[i] = ':' then
	i += 1
	do until lc[i] = ']'
		ls_idx_end = ls_idx_end + lc[i]
		i += 1
	loop
	if ls_idx_end = '' then ls_idx_end = '0'
	if not isnumber(ls_idx_end) then return -1
	ll_idx_end = long(ls_idx_end)
	if ll_idx_end > 0 and ll_idx_end < ll_idx_begin then return -1
	rst_name_exp.islist = true
else
	ll_idx_end = ll_idx_begin
	rst_name_exp.islist = false
end if

rst_name_exp.name = ls_item_name
rst_name_exp.idx_begin = ll_idx_begin
rst_name_exp.idx_end = ll_idx_end
return 0
end function

public function any getitemexp (string item_expression);any la_value,la_item_value
any la_list_get[],la_list_set[]
long i
st_name_exp lst_name_exp

setnull(la_item_value)
if _parse_expression(item_expression,lst_name_exp) < 0 then return getitem(item_expression)

la_value = getitem(lst_name_exp.name)
if isnull(la_value) then return la_item_value
if upperbound(la_value) < max(lst_name_exp.idx_begin,lst_name_exp.idx_end) then return la_item_value
la_list_get = la_value
if lst_name_exp.isList then
	if lst_name_exp.idx_end = 0 then lst_name_exp.idx_end = upperbound(la_list_get)
	for i = 1 to lst_name_exp.idx_end - lst_name_exp.idx_begin + 1
		la_list_set[i] = la_list_get[lst_name_exp.idx_begin + i - 1]
	next
	la_item_value = la_list_set
else
	la_item_value = la_list_get[lst_name_exp.idx_begin]
end if
	
return la_item_value
end function

public function integer rename (string item_name, string new_name);int li_idx

li_idx = _get_idx(item_name)
if li_idx < 0 then return -1

item_list[li_idx].name = new_name
_regenerate_items_idx()

return li_idx
end function

private function integer _trans_list (ref any value[]);long i
any la_value

for i = 1 to upperbound(value)
	la_value = value[i]
	_trans_value(la_value)
	value[i] = la_value
next

return 0
end function

private function integer _trans_value (ref any value);any la_value

if upperbound(value) >= 0 then 
	_trans_list(value)
	return 0
end if

if isnull(value) then return 0
choose case classname(value)
	case classname(this)
		la_value = value
	case 'string'
		la_value = value
	case 'integer','unsignedinteger','long','unsignedlong','decimal','double','real'
		la_value = value
	case 'boolean'
		la_value = value
	case 'date'
		la_value = string(value,date_format)
	case 'time'
		la_value = string(value,time_format)
	case 'datetime' 
		la_value = string(value,datetime_format)
	case else
		setnull(la_value)
end choose

value = la_value
return 0
end function

public function integer parse (string s);reset()
jsonstr = s
jsonc = s
jsonlen = upperbound(jsonc)

_skip()
if jsonc[idx] <> '{' then return -1
if _parse_json(this) < 0 then return -1

return 0
end function

private function boolean _check_spc (character c);
if c=' ' or c='~r' or c='~n' or c='~t' or c='~b' or c='~f' then return true
return false
end function

public function long getkeys (ref string keys[]);long i
string ls_keys[]

for i = 1 to upperbound(item_list)
	ls_keys[i] = item_list[i].name
next

keys = ls_keys
return upperbound(keys)
end function

public function integer _get_data_col (any data, ref st_data_col data_col[]);
int li_colcount
long i,j,p1,p2
string ls_tag,ls_attr_name
string ls_col_visible //mxl 20200313
any la_value

if upperbound(data) >= 0 then return -1
choose case data.dynamic typeof()
	case DataWindow!,DataStore!
	case else
		return -1
end choose

li_colcount = integer(data.dynamic describe("datawindow.column.count"))
for i = 1 to li_colcount
	ls_tag = data.dynamic describe("#"+string(i)+".tag")
	p1 = pos(ls_tag,'@attr(')
	if p1 > 0 then
		p1 += 6
		p2 = pos(ls_tag,')',p1)
		ls_attr_name = mid(ls_tag,p1,p2 - p1)
		if ls_attr_name = 'null' then continue
	else
		ls_attr_name = ''
	end if
	
	ls_col_visible = data.dynamic describe("#"+string(i)+".visible")
	if ls_col_visible = '0' then continue //列属性为隐藏则不导出 mxl 20200313
	
	j += 1
	
	data_col[j].colname = data.dynamic describe("#"+string(i)+".name")
	data_col[j].coltype = data.dynamic describe("#"+string(i)+'.coltype')
	if isnull(ls_attr_name) or ls_attr_name='' then ls_attr_name = data_col[j].colname
	data_col[j].attrname = ls_attr_name
next


return 0
end function

private function integer _trans_data_row (any data, long row, st_data_col data_col[], ref st_item rst_item[]);
long i,ll_rowcount
any la_value

ll_rowcount = data.dynamic rowcount()
if row > ll_rowcount then return -1

for i = 1 to upperbound(data_col)
	choose case lower(left(data_col[i].coltype,4))
		case 'char'	//string
			la_value = data.dynamic getitemstring(row,data_col[i].colname)
			if isnull(la_value) then la_value = ''
		case 'deci'/*decimal*/
			la_value = data.dynamic getitemdecimal(row,data_col[i].colname)
		case 'numb'/*number*/,'long','ulon'/*ulong*/,'real'
			la_value = data.dynamic getitemnumber(row,data_col[i].colname)
		case 'date'
			if data_col[i].coltype = 'date' then
				la_value = string(data.dynamic getitemdate(row,data_col[i].colname),date_format)
			else //datetime
				la_value = string(data.dynamic getitemdatetime(row,data_col[i].colname),datetime_format)
			end if
			if isnull(la_value) then la_value = ''
		case 'time'
			la_value = string(data.dynamic getitemtime(row,data_col[i].colname),time_format)
			if isnull(la_value) then la_value = ''
		case else
			setnull(la_value)
	end choose
	rst_item[i].name = data_col[i].attrname
	rst_item[i].value = la_value
next

return upperbound(rst_item)
end function

public function integer extend (n_json ajson);
st_item extend_list[]
int li_idx
int i

extend_list = ajson.item_list
for i = 1 to upperbound(extend_list)
	li_idx = _get_idx(extend_list[i].name)

	if li_idx < 0 then 
		li_idx = upperbound(item_list)+1
		item_list[li_idx] = extend_list[i]
		items_idx += extend_list[i].name+':'+string(li_idx)+'|'
	else
		item_list[li_idx].value = extend_list[i].value
	end if
next

return 0
end function

public function string stringify ();char lc_empty[]

idx = 0
jsonc = lc_empty

_stringify_json(this,1)

return jsonc
end function

public subroutine _stringify_json (n_json ajson, integer level);int i
string ls_tab

ajson._fill_jsonc('{')

if pretty_stringify then ls_tab = fill('~t',level - 1)

for i = 1 to upperbound(item_list)
	if pretty_stringify then
		ajson._fill_jsonc('~r~n~t')
		ajson._fill_jsonc(ls_tab)
	end if
	
	ajson._fill_jsonc('"')
	ajson._fill_jsonc(_trans_name(item_list[i].name))
	ajson._fill_jsonc('":')
	
	_stringify_value(ajson,item_list[i].value,level)
	
	if i < upperbound(item_list) then
		ajson._fill_jsonc(',')
	end if
next

if pretty_stringify then
	ajson._fill_jsonc('~r~n')
	ajson._fill_jsonc(ls_tab)
end if

ajson._fill_jsonc('}')

return
end subroutine

public subroutine _stringify_list (n_json ajson, any value[], integer level);long i

ajson._fill_jsonc('[')

for i = 1 to upperbound(value)
	_stringify_value(ajson,value[i],level)
	if i < upperbound(value) then
		ajson._fill_jsonc(',')
	end if
next

ajson._fill_jsonc(']')

return



end subroutine

public subroutine _stringify_value (n_json ajson, any value, integer level);string ls_value
n_json ljson
char lc_tmp[]
long i

if upperbound(value) >= 0 then
	_stringify_list(ajson,value,level)
elseif classname(value) = classname(this) then
	ljson = value
	ljson.item_name_style = item_name_style
	ljson.pretty_stringify = pretty_stringify
	ljson._stringify_json(ajson,level + 1)
else
	if isnull(classname(value)) then
		ajson._fill_jsonc('null')
	else
		choose case classname(value)
			case 'string'
				ajson._fill_jsonc('"')
				lc_tmp = string(value)
				for i = 1 to upperbound(lc_tmp)
					if asc(lc_tmp[i]) > 127 then
						//防止汉字GBK编码后半部分包含\等特殊符号 MXL 20200326
						ajson._fill_jsonc(lc_tmp[i] + lc_tmp[i + 1])
						i ++
						continue
					end if
					choose case lc_tmp[i]
						case '\'
							ajson._fill_jsonc('\')
							if i < upperbound(lc_tmp) then //防止数组越界 MXL 20200326
								if lc_tmp[i + 1] = 'u' then continue
							end if
							ajson._fill_jsonc('\')
						case '"'
							ajson._fill_jsonc('\' + lc_tmp[i])
						case '~r'
							ajson._fill_jsonc('\r')
						case '~n'
							ajson._fill_jsonc('\n')
						case '~t'
							ajson._fill_jsonc('\t')
						case '~f'
							ajson._fill_jsonc('\f')
						case '~b'
							ajson._fill_jsonc('\b')
						case else
							ajson._fill_jsonc(lc_tmp[i])
					end choose
				next
				ajson._fill_jsonc('"')
			case else
				ajson._fill_jsonc(string(value))
		end choose
	end if
end if

return 

end subroutine

public subroutine _fill_jsonc (string s);char lc[]
long i

lc = s
for i = 1 to upperbound(lc)
	idx ++
	jsonc[idx] = lc[i]
next
end subroutine

public function integer setsql (string item_name, string sql);datastore lds_data

if _sql_to_ds(sql,lds_data) < 0 then return -1

return setdata(item_name,lds_data)
end function

public function integer setsqlrow (string sql, long row);datastore lds_data

if _sql_to_ds(sql,lds_data) < row then return -1

return setdatarow(lds_data,row)
end function

public function boolean hasitem (string item_name);return _get_idx(item_name) > 0
end function

public function integer setsqlrow (string item_name, string sql, long row);datastore lds_data

if _sql_to_ds(sql,lds_data) < row then return -1

return setdatarow(item_name,lds_data,row)
end function

public function integer setsqlrow (string item_name, string sql, long begin_row, long end_row);datastore lds_data

if _sql_to_ds(sql,lds_data) < end_row then return -1

return setdatarow(item_name,lds_data,begin_row,end_row)
end function

public function long _sql_to_ds (string sql, ref datastore ds);string ls_syntax
string ls_err

ls_syntax = SQLCA.SyntaxFromSQL(sql,'Style(Type=Grid)',ls_err)
if len(ls_err) > 0 then return -1

ds = create datastore
ds.create(ls_syntax,ls_err)
if len(ls_err) > 0 then return -1

ds.settransobject(SQLCA)
ds.retrieve()

return ds.rowcount()
end function

private function decimal _to_number (string s);//新增功能:将字符串转换成数字 mxl 20200326
dec ldc

setnull(ldc)
if not (isnumber(s)) then return ldc
ldc = dec(s)

return ldc
end function

on n_json.create
call super::create
TriggerEvent( this, "constructor" )
end on

on n_json.destroy
TriggerEvent( this, "destructor" )
call super::destroy
end on



  • 6
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
本次开源项目为JSON系列整套解决方案。*本方案可自动生成json索引表达式和排除json语法错误以及生成json文本等功能。 *混E官方论坛的应该了解该方案可以说是目前易语言 json开发方面最高开发效率的 成熟解决 方案。*最版本2.1代码全部由@天朝红雨亲手编写,未参照任何开源算法,本版本精易论坛 首发! *2.1版本相对2.0版本改进:1.核心 :修复 删除项目时成员数不更BUG。2. 修复【严格模式】时逗号结尾不报错BUG。3.编辑器: 修复 全部替换无法撤销BUG。4. 增加 向后插入项目。 类_JSON_ :已实现JSON解析、生成、编辑的整套方案,并已封装成模块。 未参照任何开源解析算法,经过多次改进已然成为了一个稳定强大的json处理核心。 类_格式化JSON_快速:以 类的形式对json文本格式化和反格式化 , 类的封装意味着一段超长文本可以分几次加入是没有问题的,不再担心卡机。 JSON调试器: JSON解析模块的附属品,也算是模块的例程,依托强大的 JSON解析、编辑核心已然可以说是最强大的JSON视图调试器,助您快速准确的找出json文本中的错误原因。 升级说明文档: JSON解析模块改进: 严格模式: A:JSON解析模块2.0加入了“严格模式”。 B:非“严格模式”下忽略一切错误。 C:“严格模式”下一但遇到语法错误将停止解析并返回错误信息。 顶级对象命名: A:模块在2.0版本中自创“顶级对象命名”模式。 B:故名思意,就是假设顶级对象也是某个对象的成员,所以允许命名。 C:这样在编辑时可以避免名称损失,但注意顶级对象命名不是标准的JSON规范! 其他改进: A:模块以前的方法命名比较接近“精易模块 ”2.0版本开始有很大调整。 B:“取通用属性()”方法现已更名“取项目值()并且参数不再向下兼容”具体用法参照本调试器。 C:加入更多对JSON对象安全的修改功能比如“置项目数据()”\“置项目值()”等。 D:加入对象或编辑器之间的沟通如“取项目数据()”\“取项目数据文本()”等。 E:修复文本转义时因常量指针造成的崩溃 。 F:更多使用改进内容请查看模块内部说明… 调试器改进: 相对于1.3版本JSON调试器: A:增加“语法高亮”。 B:默认情况下黑色文字说明出现了语法错误。 C:当出现灰色文字时说明出现了人们经常犯的语法错误。 D:增加代码“反格式化” E:更多改进请使用时体会… 基于@云外归鸟的“开源PB编辑器”的改进: A:修复编辑器频繁崩溃。 B:改进TAB画图方式为标准的分组对齐方式。 C:修复编辑器撤销出错BUG D:其他热键支持和Windows基础交互支持 对于严格模式我建议调试时启用,可以快速找到错误, 而发布后则关闭严格模式以最大的可能去兼容来自各路神仙生成的json代码文本, 保证程序顺利执行 。 引用了一个【异编自校验模块】易语言自校验模块鼻祖级别产品,也是开源产品,源码论坛搜索。 鸣谢:云外归鸟、易语言软件开发有限公司
JSONPB是指将JSON格式的数据转换为Protobuf(PB)的数据结构和格式。对于C语言,可以使用相应的PB库来完成这个转换过程。 首先,需要将JSON数据解析成一个C语言的结构体,然后根据PB消息定义,将解析出的数据赋值给对应的PB字段。 其次,需要使用PB库提供的函数将结构体的数据序列化成二进制的PB格式。这个过程中,PB库会自动根据PB消息定义对数据进行编码,生成二进制的PB消息。 最后,将生成的二进制数据写入文件或通过网络传输等方式进行存储或传输。 以下是一个简单的C语言示例代码,展示从JSON转换为PB的过程: ```c #include <stdio.h> #include "pb_decode.h" // PB解码库 #include "pb_encode.h" // PB编码库 #include "my_message.pb.h" // PB消息定义 void json_to_pb(const char* json_data) { // 解析JSON数据到C语言结构体 MyMessage my_message = MyMessage_init_zero; pb_istream_t json_input = pb_istream_from_buffer(json_data, strlen(json_data)); pb_decode(&json_input, MyMessage_fields, &my_message); // 将C语言结构体数据序列化为PB格式 uint8_t pb_buffer[128]; pb_ostream_t pb_output = pb_ostream_from_buffer(pb_buffer, sizeof(pb_buffer)); pb_encode(&pb_output, MyMessage_fields, &my_message); // 将PB格式数据写入文件或传输 // ... printf("转换成功!\n"); } int main() { const char* json_data = "{\"name\":\"Alice\",\"age\":20}"; json_to_pb(json_data); return 0; } ``` 上述代码中,假设已定义了一个名为`MyMessage`的PB消息,并包含名为`name`和`age`的字段。`json_data`为待转换的JSON数据。通过调用`json_to_pb`函数实现JSONPB的转换。最后输出提示信息表示成功转换。 需要注意的是,上述代码仅为参考示例,实际使用时需要根据具体的PB消息定义和PB库的使用方式进行相应的修改和调整。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值