hb_jsondecode + hb_jsonEncode

2,107 views
Skip to first unread message

Serge Girard

unread,
Feb 16, 2017, 5:58:09 AM2/16/17
to Harbour Users
Hello,

I try to generate a JSON file from a DBF-file which should contain:
- dbf structure (fieldnames)
- dbf data

This works and the generated file is OK according http://jsonlint.com/

When I try to reload the JSON file it gives: Error BASE/1068 Argument error: array access

See the coding I use:
Either my create is wrong or decode doesn't work properly? Can anybody please shine a light on this?

Thanks, Serge
Geef de code hier op...



PROCEDURE MAIN
/************/

CREATE_JSON()
READ_JSON()

QUIT






FUNCTION CREATE_JSON()
/********************/
LOCAL res
LOCAL o, a, t
LOCAL aSTRUCT, aARRAY, aHash
LOCAL cJson1, cJson2, mFIELD1
LOCAL cTMP

USE  P:\TEST\LANDEN
 
aSTRUCT  := DBSTRUCT()
aARRAY   := {}
aHash    := HASH()
aHash ["FLD_CNT"] := ALLTRIM(STR(LEN(aSTRUCT))) // ADD NUMBER OF FIELDS

FOR a = 1 TO LEN(aSTRUCT)  // ADD HEADER NAMES
   cTMP     := '"FLD_' + ALLTRIM(STR(a)) + '"'
   mFIELD1  := aSTRUCT [a] [1] 
   aHash [&cTMP] := mFIELD1
NEXT
AADD(aARRAY, aHash)

 


// CREATE DETAILS 
aHash    := hash()
 
GO TOP
t := 1
DO WHILE .NOT. EOF()
   t++
   aHash    := hash()
   FOR a = 1 TO LEN(DBSTRUCT())  
      mFIELD1 := aSTRUCT [a] [1] 
      aHash [aSTRUCT [a] [1]] := ALLTRIM(&mFIELD1)   // FIELDNAMES
   NEXT     
  
   AADD(aARRAY, aHash)
 
   
   IF t >= 5 // LIMIT OUTPUT FOR TEST
      EXIT
   ENDIF 
  
   SKIP
ENDDO
CLOSE ALL


cJson1 := hb_jsonEncode(aARRAY,.T.)

lSUCCES  := MEMOWRIT( 'JSON6.TXT' , cJson1) 
// http://jsonlint.com/    --> ok
RETURN





FUNCTION READ_JSON()
/***********************/
LOCAL nLen, cTEXT
LOCAL res
LOCAL o
LOCAL cTEMP, A, aARRAY_JSON
STATIC cFLD , nFLD_CNT

cFLD := '"FLD_CNT"'

cTEXT := memoread( "JSON6.TXT" )   // HEADERS + DATA
nLen  := hb_jsondecode( cTEXT, @res )

IF nLen == 0
   ? "Quitting (JSON6.TXT incorrect structure) : nLen==0 "
   QUIT
ENDIF
 
nFLD_CNT    := val(Strvalue(res["FLD_CNT"]))  // SHOULD RESULT IN  4 BUT GIVES: Error BASE/1068 Argument error: array access

 
aARRAY_JSON := {}
FOR a = 1 TO nFLD_CNT
   cFLD := '"FLD_' + ALLTRIM(STR(a)) + '"'
   ? cFLD
   AADD(aARRAY_JSON, Strvalue(res[&cFLD])) 
NEXT

o := 0
FOR EACH o IN res   
   cTEMP := ''
   FOR A = 1 TO nFLD_CNT
      cTEMP += Strvalue(o[ aARRAY_JSON [A]])  + ' '  
   NEXT
   ? 'cTEMP ' , cTEMP
NEXT


RETURN




 
FUNCTION Strvalue( string )
/*********************************/
LOCAL retval := ''

DO CASE
CASE VALTYPE( string ) == 'C'
    retval := string

CASE VALTYPE( string ) == 'N'
    retval := LTRIM( STR( string ) )

CASE VALTYPE( string ) == 'M'
    retval := IF( (LEN(string) > (MEMORY(0) * 1024) * .80), ;
                        SUBSTR(string,1, INT((MEMORY(0) * 1024) * .80)), ;
                        string )

CASE VALTYPE( string ) == 'D'
    retval := DTOC( string )

CASE VALTYPE( string ) == 'L'
    retval := IF(string, "True", "False")
  
OTHERWISE
    retval := ''

ENDCASE

RETURN( retval )
 

Serge Girard

unread,
Feb 17, 2017, 4:03:00 AM2/17/17
to Harbour Users
Nobody ?


Op donderdag 16 februari 2017 11:58:09 UTC+1 schreef Serge Girard:

Fausto

unread,
Feb 17, 2017, 6:29:22 AM2/17/17
to harbou...@googlegroups.com
Hello,

In READ_JSON(), res is an array of hashes, then you need:

nFLD_CNT    := val(Strvalue(res[1,"FLD_CNT"]))

and below

AADD(aARRAY_JSON, Strvalue(res[1,&cFLD]))

and in


FOR EACH o IN res  
   cTEMP := ''
   FOR A = 1 TO nFLD_CNT
      IF HB_HHASKEY( o, aARRAY_JSON [A] )

         cTEMP += Strvalue(o[aARRAY_JSON [A]])  + ' ' 
      ENDIF

   NEXT
   ? 'cTEMP ' , cTEMP
NEXT

The first o is the hash with the structures and it doesn´t have the field name as a hash key, you can use HB_HHASKEY() to verify if the key exists in hash.

To list the values of the res hash and help to understand how the hb_jsondecode() returns res, you can use:
? VALTOPRG( res )

Fausto Di Creddo Trautwein
--
--
You received this message because you are subscribed to the Google
Groups "Harbour Users" group.
Unsubscribe: harbour-user...@googlegroups.com
Web: http://groups.google.com/group/harbour-users

---
You received this message because you are subscribed to the Google Groups "Harbour Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to harbour-user...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Klas Engwall

unread,
Feb 17, 2017, 6:33:09 AM2/17/17
to harbou...@googlegroups.com
Hi Serge,

> I try to generate a JSON file from a DBF-file which should contain:
> - dbf structure (fieldnames)
> - dbf data
>
> This works and the generated file is OK according http://jsonlint.com/
>
> When I try to reload the JSON file it gives: Error BASE/1068 Argument
> error: array access
>
> See the coding I use:
> Either my create is wrong or decode doesn't work properly? Can anybody
> please shine a light on this?

I can assure you that hb_JsonDecode() is working properly on a valid
json file. But ...

... I gave it a shot yesterday and tried to run your code. First I had
to replace your calls to the xHarbour function Hash() in three places.
Use Harbour functions instead (see the list below).

Then it stopped with:
Error DBFNTX/1001 Open error: P:\TEST\LANDEN.dbf (DOS Error 3)
Called from DBUSEAREA(0)
Called from CREATE_JSON(22)
Called from MAIN(4)

I didn't have time to investigate the code to see what that dbf file
should look like. If you post code here, we need it to be self contained
(== complete).

There are many hash related functions that can help you find out what is
wrong. hb_HHasKey() will tell you if a certain key exists, for example,
or hb_HPos() will tell you the hash member's position in the hash.

You are using macro substitution blindly to access the members of the
hash that you call "res". If you use hb_HPos() to find the member's
position you can exit gracefully if it is not found. Then hb_HGet() will
give you the value, or hb_HPairat() will give you both the key and the
value as an array.

Here is a list of all the available hash functions:

HB_HASH( [ <Key1>, <Value1> ], [ <KeyN>, <ValueN> ], ... ) -> <hsTable>
HB_HHASKEY( <hsTable>, <Key> [, @nPos ] ) --> <lFound>
HB_HPOS( <hsTable>, <Key> ) -> nPosition
HB_HGET( <hsTable>, <Key> ) -> <Value>
HB_HGETDEF( <hsTable>, <Key>, [<DefaultValue>] ) -> <Value>
HB_HSET( <hsTable>, <Key>, <Value> ) -> <hsTable>
HB_HDEL( <hsTable>, <Key> ) -> <hsTable>
HB_HKEYAT( <hsTable>, <nPosition> ) -> <Key>
HB_HVALUEAT( <hsTable>, <nPosition>, [<NewValue>] ) -> <Value>
HB_HPAIRAT( <hsTable>, <nPosition> ) -> <aKeyValue>
HB_HDELAT( <hsTable>, <nPosition> ) -> <hsTable>
HB_HKEYS( <hsTable> ) -> <aKeys>
HB_HVALUES( <hsTable> ) -> <aValues>
HB_HCLEAR( <hsTable> ) -> <hsTable>
HB_HFILL( <hsTable>, <Value> ) -> <hsTable>
HB_HCLONE( <hsTable> ) -> <hsDestination>
HB_HCOPY( <hsDestination>, <hsSource>, [<nStart>], [<nCount>] ) ->
<hsDestination>
HB_HMERGE( <hsDestination>, <hsSource>, <bBlock>|<nPosition> ) ->
<hsDestination>
HB_HEVAL( <hsTable>, <bBlock>, [<nStart>], [<nCount>] ) -> <hsTable>
HB_HSCAN( <hsTable>, <Value>, [<nStart>], [<nCount>, [<lExact>] ) ->
nPosition
HB_HSORT( <hsTable> ) -> <hsSortedTable>
HB_HCASEMATCH( <hsTable>, [<lFlag>] ) -> <lPreviousFlag>
HB_HBINARY( <hsTable>, [<lFlag>] ) -> <lPreviousFlag>
HB_HAUTOADD( <hsTable>, [<nAutoAdd>|<lAutoAdd>], [<xDefault>] ) ->
<nOldAutoAdd>
HB_HKEEPORDER( <hsTable>, [<lFlag>] ) -> <lPreviousFlag>
HB_HALLOCATE( <hsTable>, <nItems> )
HB_HDEFAULT( <hsTable>, <DefaultValue> ) -> <OldDefaultValye>
HB_HGETREF( <hsTable>, <Key>[, <@Value> ] ) -> <lFound>
HB_HSETORDER( <hsTable> [, <lNewSetting> ] ) -> <hsTable>

Regards,
Klas

Serge Girard

unread,
Feb 17, 2017, 7:00:37 AM2/17/17
to Harbour Users
Thx Fausto, This works !

Thx Klas, Sorry that I forgot to include the DBF file. I thought one could imagine that it should work with ANY DBF-file !
Anyway thanks to the both for answering!

Serge


Op donderdag 16 februari 2017 11:58:09 UTC+1 schreef Serge Girard:
Hello,

Klas Engwall

unread,
Feb 17, 2017, 8:14:46 AM2/17/17
to harbou...@googlegroups.com
Hi Serge.

> Thx Fausto, This works !
>
> Thx Klas, Sorry that I forgot to include the DBF file. I thought one
> could imagine that it should work with ANY DBF-file !

You know what your code does. Everyone else must read all the hundred
lines of it to understand what you mean. That is a waste of time. Common
practice is to create and populate necessary data files at the top of
the sample code so anyone can run it quickly and get to the real problem
with no extra hassle.

Regards,
Klas

vszakats

unread,
Feb 17, 2017, 9:26:40 AM2/17/17
to Harbour Users

... I gave it a shot yesterday and tried to run your code. First I had
to replace your calls to the xHarbour function Hash() in three places.

Short alternative that works everywhere: { => }

Serge Girard

unread,
Feb 17, 2017, 10:07:37 AM2/17/17
to Harbour Users
Thx !


Op donderdag 16 februari 2017 11:58:09 UTC+1 schreef Serge Girard:
Hello,
Reply all
Reply to author
Forward
0 new messages