Searching for Json elements...

Share your advanced PureBasic knowledge/code with the community.
User avatar
Michael Vogel
Addict
Addict
Posts: 2663
Joined: Thu Feb 09, 2006 11:27 pm
Contact:

Searching for Json elements...

Post by Michael Vogel »

Hi,
I need to parse json configuration files to find certain elements, so I started to create 'JsonScan' which is doing that stuff and return the found element type or -1 if the search fails. The example shows a file of the Garmin IQ SDK which allows to write programs for their sport watches.

JsonScan(object,"name") will return the object 'name' if found, where name may also include the hierarchical path to the object (like 'display/location/width').

I haven't implemented all Json types but beside standard objects the following types are supported: numbers, strings and arrays. For arrays, the index of the array could also be used in the object path, like in 'keys/1/location/width'.

Code: Select all


jsonfile.s="{|'display': {|'behaviors': [],|'isTouch': false,|'landscapeOrientation': 0,|'location': {|'height': 240,|'width': 240,|'x': 105,|'y': 145|},|'shape': 'round'|},|'fonts': [|{|'fontSet': 'ww',|'fonts': [|{|'filename': 'FNT_FENIX5_CHRONOSSEMIBOLDCONDENSED_58PX',|'name': 'systemNumberThaiHot'|}|]|},|{|'fontSet': 'apac_jpn',|'fonts': [|{|'filename': 'FNT_FENIX5_CHRONOSSEMIBOLDCONDENSED_58PX',|'name': 'systemNumberThaiHot'|}|]|},|{|'fontSet': 'apac_tha',|'fonts': [|{|'filename': 'bitstreamVeraSans 16',|'name': 'xtiny'|},|{|'filename': 'FNT_FENIX5_CHRONOSSEMIBOLDCONDENSED_58PX',|'name': 'systemNumberThaiHot'|}|]|}|],|'image': 'forerunner_935.png',|'keys': [|{|'behavior': 'onSelect',|'id': 'enter',|'location': {|'height': 52,|'width': 38,|'x': 377,|'y': 165|}|},|{|'behavior': 'previousPage',|'id': 'up',|'location': {|'height': 57,|'width': 25,|'x': 25,|'y': 244|}|},|{|'behavior': 'onMenu',|'id': 'menu',|'isHold': true,|'location': {|'height': 57,|'width': 25,|'x': 25,|'y': 244|}|},|{|'behavior': 'nextPage',|'id': 'down',|'location': {|'height': 52,|'width': 32,|'x': 41,|'y': 327|}|},|{|'id': 'clock',|'isHold': true,|'location': {|'height': 52,|'width': 32,|'x': 41,|'y': 327|}|},|{|'behavior': 'onBack',|'id': 'esc',|'location': {|'height': 60,|'width': 33,|'x': 376,|'y': 321|}|}|],|'layouts': [|{|'datafields': {|'datafields': [|{|'drawBorders': true,|'fields': [|{|'data': {|'font': 'numberThaiHot',|'justification': 'center',|'width': 192,|'x': 119,|'y': 157|},|'obscurity': [|'left',|'top',|'right',|'bottom'|]|}|],|'name': '1 Field'|},|{|'drawBorders': true,|'fields': [|{|'data': {|'font': 'numberThaiHot',|'justification': 'center',|'width': 154,|'x': 120,|'y': 115|},|'label': {|'font': 'tiny',|'justification': 'center',|'x': 119,|'y': 47|},|'labelDisabled': false,|'location': {|'height': 119,|'width': 240,|'x': 0,|'y': 0|},|'obscurity': [|'left',|'top',|'right'|]|},|{|'data': {|'font': 'numberThaiHot',|'justification': 'center',|'width': 154,|'x': 120,|'y': 89|},|'label': {|'font': 'tiny',|'justification': 'center',|'x': 119,|'y': 22|},|'labelDisabled': false,|'location': {|'height': 119,|'width': 240,|'x': 0,|'y': 121|},|'obscurity': [|'left',|'right',|'bottom'|]|}|],|'name': '2 Fields'|},|{|'drawBorders': true,|'fields': [|{|'data': {|'font': 'numberMedium',|'justification': 'center',|'width': 132,|'x': 120,|'y': 74|},|'label': {|'font': 'tiny',|'justification': 'center',|'x': 119,|'y': 29|},|'labelDisabled': false,|'location': {|'height': 77,|'width': 240,|'x': 0,|'y': 0|},|'obscurity': [|'left',|'top',|'right'|]|},|{|'data': {|'font': 'numberMild',|'justification': 'center',|'width': 96,|'x': 54,|'y': 62|},|'label': {|'font': 'tiny',|'justification': 'center',|'x': 54,|'y': 23|},|'labelDisabled': false,|'location': {|'height': 119,|'width': 119,|'x': 121,|'y': 121|},|'obscurity': [|'right',|'bottom'|]|}|],|'name': '4 Fields B'|}|]|},|'menu2': {|'customTitle': {|'height': 52,|'width': 126,|'x': 57,|'y': 18|},|'doneButtons': {|'bottom': true,|'top': true|},|'items': {|'checks': [|{|'alignment': 'left',|'disabledIconFile': 'menu2_check_off_vegas.png',|'enabledIconFile': 'menu2_check_on_vegas.png',|'x': 11,|'y': 32|},|{|'alignment': 'right',|'disabledIconFile': 'menu2_check_off_vegas.png',|'enabledIconFile': 'menu2_check_on_vegas.png',|'x': 199,|'y': 32|}|],|'icons': {|'check': 'left',|'icon': 'left',|'leftLocation': {|'height': 82,|'width': 41,|'x': 3,|'y': 7|},|'rightLocation': {|'height': 82,|'width': 41,|'x': 196,|'y': 7|},|'toggle': 'right'|},|'item': {|'height': 96,|'labelFont': 'large',|'subLabelFont': 'small',|'width': 240|},|'region': {|'height': 96,|'width': 240,|'x': 0,|'y': 72|},|'stringWidths': {|'basic': 224,|'check': 152,|'icon': 152,|'toggle': 200|},|'subItem': {|'height': 51,|'labelFont': 'tiny',|'labelWidth': 178,|'yOffset': 2|},|'toggles': [|{|'alignment': 'left',|'disabledIconFile': 'menu2_toggle_off_left_240x240.png',|'enabledIconFile': 'menu2_toggle_on_left_240x240.png',|'x': 3,|'y': 7|},|{|'alignment': 'right',|'disabledIconFile': 'menu2_toggle_off_right_240x240.png',|'enabledIconFile': 'menu2_toggle_on_right_240x240.png',|'x': 220,|'y': 7|}|]|},|'title': {|'height': 72,|'width': 240,|'x': 0,|'y': 0|},|'titleString': {|'font': 'tiny',|'width': 120,|'x': 119,|'y': 42|}|},|'orientation': 'portrait',|'picker': {|'entries': [|{|'height': 132,|'width': 65,|'x': 11,|'y': 80|},|{|'height': 132,|'width': 65,|'x': 87,|'y': 80|},|{|'height': 132,|'width': 65,|'x': 164,|'y': 80|}|],|'title': {|'height': 66,|'width': 240,|'x': 0,|'y': 0|}|}|}|],|'sensorHistory': [|{|'interval': 120,|'size': 120,|'type': 'heartrate'|},|{|'interval': 72,|'size': 200,|'type': 'elevation'|},|{|'interval': 72,|'size': 200,|'type': 'temperature'|},|{|'interval': 72,|'size': 200,|'type': 'pressure'|}|],|'watchdogCount': 120000|}"

jsonfile=ReplaceString(jsonfile,"'",#DOUBLEQUOTE$)
jsonfile=ReplaceString(jsonfile,"|",#CRLF$)



Structure JsonType
	parent.i
	object.i
	name.s
	valtext.s
	valnumber.i
	type.i
	depth.i
EndStructure

Global Jay.JsonType

#Undefined=		-#True
#Seperator=		"/"

Macro JsonFound(okay)

	If depth=CountString(object,#Seperator)+1
		Jay\name=JSONMemberKey(json)
		Jay\object=JSONMemberValue(json)
		Jay\type=JSONType(Jay\object)
		Jay\valtext=""
		Jay\valnumber=#Null

		; Debug "type "+Jay\type
		Select Jay\type
		Case #PB_JSON_Number
			Jay\valnumber=GetJSONInteger(Jay\object)
		Case #PB_JSON_String
			Jay\valtext=GetJSONString(Jay\object)
		Case #PB_JSON_Array
			Jay\valnumber=JSONArraySize(Jay\object)
		Default
			Debug "Other type: "+Str(Jay\type)
		EndSelect

		ProcedureReturn Jay\type

	ElseIf JSONType(json)=#PB_JSON_Object

		If okay=0
			json=JSONMemberValue(json)
		EndIf
		ProcedureReturn JsonScan(json,object,depth)

	Else
		Debug "error"

	EndIf

EndMacro
Procedure JsonScan(json,object.s,depth=#Null)

	Protected o
	Protected check.s

	;Debug "=== "+depth+" ===  "+json

	With Jay

		If json
			\parent=json
			depth+1

			Select JSONType(json)

			Case #PB_JSON_Object
				check=StringField(object,depth,#Seperator)
				If ExamineJSONMembers(json)

					While NextJSONMember(json)
						;Debug "> "+JSONMemberKey(json)
						If JSONType(JSONMemberValue(json))
						EndIf

						If JSONMemberKey(json)=check
							JsonFound(0)
						EndIf

					Wend
				EndIf

			Case #PB_JSON_Array
				;Debug ">>>> "+StringField(object,depth,#Seperator)
				json=GetJSONElement(json,Val(StringField(object,depth,#Seperator))-1)
				If json
					JsonFound(1)
				EndIf
				Debug "Hm.."

			EndSelect

		Else
			\parent=#Null
			ProcedureReturn #Null

		EndIf

	EndWith

EndProcedure


;n=LoadJSON(0,s,#PB_JSON_NoCase)
n=ParseJSON(0,jsonfile,#PB_JSON_NoCase)
If n
	n=JSONValue(0)

	If JsonScan(n,"display/location/width")=#PB_JSON_Number
		Debug jay\name+" = "+Str(jay\valnumber)
	EndIf
	If JsonScan(n,"display/location/height")=#PB_JSON_Number
		Debug jay\name+" = "+Str(jay\valnumber)
	EndIf
	If JsonScan(n,"display/shape")=#PB_JSON_String
		Debug jay\name+" = "+jay\valtext
	EndIf
	If JsonScan(n,"display/location/x")=#PB_JSON_Number
		Debug jay\name+" = "+Str(jay\valnumber)
	EndIf
	If JsonScan(n,"display/location/y")=#PB_JSON_Number
		Debug jay\name+" = "+Str(jay\valnumber)
	EndIf

	If JsonScan(n,"keys")=#PB_JSON_Array
		z=jay\valnumber
		For i=1 To z
			If JsonScan(n,"keys/"+Str(i)+"/id")=#PB_JSON_String
				Debug jay\valtext
				If JsonScan(n,"keys/"+Str(i)+"/location/height")=#PB_JSON_Number
					Debug jay\name+" = "+Str(jay\valnumber)
				EndIf
				If JsonScan(n,"keys/"+Str(i)+"/location/width")=#PB_JSON_Number
					Debug jay\name+" = "+Str(jay\valnumber)
				EndIf
			EndIf
		Next i
		Debug "ok"
	EndIf

	If ExamineJSONMembers(n)
		While NextJSONMember(n)
			;Debug JSONMemberKey(n) + " = " ;+ GetJSONInteger(JSONMemberValue(n))
			If JSONType(n)=#PB_JSON_Array
				;Debug "*"
			EndIf
		Wend
	EndIf
EndIf