Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations gkittelson on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

njJson : not succeeding to get it work 3

Status
Not open for further replies.

Rajesh Karunakaran

Programmer
Sep 29, 2016
549
MU
Hi friends,

I downloaded the nfJson library from gitHub and the provided examples PRG files are working properly.

I have a json file, from which I want to retrieve data and populate a cursor. I have seen a PRG in nfJson 'nfopenjson.prg'. The example provided for that prg works fine. However, when I try to apply that to a slightly different structured json file, I am getting 'Syntax error' message.

Below is the content of the JSON file:

Code:
{
  "master" : {
    "decRef" : {
      "msgTyp" : "F",
      "prtofRptng" : "INNSA1",
      "jobNo" : 12345,
      "jobDt" : "20190806",
      "rptngEvent" : "SAM",
      "mnfstNoRotnNo" : 175912,
      "mnfstDtRotnDt" : "20190716",
      "vesselTypMvmt" : "FI"
    }
  }
}

Below is the program that I am trying:

Code:
lcJson = FILETOSTR('sampleValues.json')
=nfOpenJson(lcJson,'$.array', ' ;
		- msgTyp        v(1)  $.master.msgTyp ;
		- prtofRptng    v(20) $.master.prtofRptng')
BROWSE

I am just checking with retrieving only 2 columns. But, when I run this, I am getting 'Syntax error'.
Can anyone help me to find out the problem? What I am missing?

Thank you very much in advance,
Rajesh


 
OK, best wishes for your progress.

If you show how you create the JSON, this might get a good idea to get back to the original data. You might have used TEXT..ENDTEXT (Textmerge). It's not always straight forward to get back data as it was.

I could only recommend in general, that under that circumstance you only need the JSON to exchange data coming from VFP and retrieved back in VFP, when there is nothing else involved needing specific JSON, I'd rather use CURSORTOXML/XMLTOCURSOR. That has a dependency to MSXML3 and 4, but it's workable and has much less headaches in the reversal of generating and parsing. Besides being able to exchange DBF files of free DBFs.


It's a fine idea to keep the JSON shorter, concentrating the information into a single bracket, for example, but as you see the natural way to read this in does not generate a collection of 4 objects or an array with 4 rows, but a single object with 4 properties.

I can imagine you used a SCAN-LOOP to read out name/value and put that into the rows of the single JSON notation. If you read that back, you therefore also need a loop to read out the four properties and split them up and insert them into four records. And that's less straight forward, as you need the list of members for the reverse way. You sacrificed the simple reverse transformation for shorter JSON notation.

Bye, Olaf.

Olaf Doschke Software Engineering
 
Hello Rajesh, after inspecting in more detail you object ( let's forget about it is serialized as json ) the structure shows -as you already said- that it was not generated 'as is' from a relational db ( that's ok ) so trying to turn it into related tables defeats the intention to work with a model that it's thinked to closely represent a entity. Json came into the scene in MySql, Postgres, Sqlserver etc. precisely to bring into the RDBMS world that "noSql" capacities, so the desired way to work with this object is 'as is' by just parsing it with nfJsonRead.

If we need to turn it into parent-child cursors, or even completely flatten the structure, we should:

1) create the related tables ( target tables ) with the columns matching the names of the source objects
2) append blank record on each taget table and proceeed to apply successive "gather name" over it with
source object properties until it has collected all the desired ones ( that's a cool feature of vfp that allows to make an object patch using a table record instead of an object! )
3) iterate arrays, using the same steps above.

Here is the basic technique ( of course I'll leave to you the more complex nested tables ;-) )

Code:
*------------------------------------------------
* using nfJsonRead to flatten object structures
*------------------------------------------------

Close Tables All

Public ojson

ojson =  nfjsonread( getjson() )


*-- this cursor will get properties from multiple source objects - 2 properties from each taken as sample: 
Create Cursor flattenSample  ( ;
  senderid c(10),receiverid c(10),;
  msgtyp   c(10),prtofrptng c(10),;
  sbmtrtyp c(10),sbmtrcd    c(10),;
  modeoftrnsprt c(10),grosstonnage N(10,2),;
  voyageno c(10) ,totalnooftrnsprteqmtmnfsted i )


Create Cursor shipitnry  (;
  shipitnryseq c(10),;
  prtofcallcdd c(10),;
  prtofcallname c(10) )

Select flattenSample

Append Blank
Gather Name ojson.headerfield
Gather Name ojson.Master.decref
Gather Name ojson.Master.authprsn
Gather Name ojson.Master.vesseldtls
Gather Name ojson.Master.voyagedtls
edit normal


* observe that only the last entry has all the shipitnry properties
* this is how "object patch" works in vfp using cursor rows

Select shipitnry

For Each oshipitnry In   ojson.Master.voyagedtls.shipitnry
  Append Blank
  Gather Name oshipitnry
Endfor
browse normal



*--------------------------------------
Function getjson()
*--------------------------------------

TEXT TO cjson NOSHOW TEXTMERGE

{
  "HeaderField": {
    "senderID": "FARSHIPPING",
    "receiverID": "INCCU1",
    "versionNo": "1.1.0.2",
    "indicator": "T",
    "messageID": "SACHM23",
    "sequenceOrControlNumber": "1234",
    "date": "20190902",
    "time": "18:59:39",
    "reportingEvent": "SAM"
  },
  "master": {
    "decRef": {
      "msgTyp": "F",
      "prtofRptng": "INCCU1",
      "jobNo": 1234,
      "jobDt": "20190902",
      "mnfstNoRotnNo": 0,
      "vesselTypMvmt": "C",
      "dptrMnfstNo": 0
    },
    "authPrsn": {
      "sbmtrTyp": "ASA",
      "sbmtrCd": "ADSPD9028J",
      "authReprsntvCd": "BXQPD10234",
      "shpngLineCd": "AAFFH9326F",
      "authSeaCarrierCd": "AAHFB9023F",
      "trmnlOprtrCd": "INCCU1KKP1"
    },
    "vesselDtls": {
      "modeOfTrnsprt": "1",
      "grossTonnage": 0.000,
      "netTonnage": 0
    },
    "voyageDtls": {
      "voyageNo": "001",
      "totalNoOfTrnsprtEqmtMnfsted": 4,
      "briefCrgoDesc": "GENERAL CARGO",
      "totalNmbrOfLines": 15,
      "exptdDtAndTimeOfArvl": "20190829T9T12:51",
      "nmbrOfPsngrsMnfsted": 0,
      "nmbrOfCrewMnfsted": 0,
      "shipItnry": [{
        "shipItnrySeq": "-3"
      },
      {
        "shipItnrySeq": "-2"
      },
      {
        "shipItnrySeq": "-1",
        "prtOfCallCdd": "LKCMB"
      },
      {
        "shipItnrySeq": "0",
        "prtOfCallCdd": "INCCU1",
        "prtOfCallName": "KOLKAT"
      }]
    },
    "mastrCnsgmtDec": [{
      "MCRef": {
        "lineNo": 1,
        "mstrBlNo": "SCJUA37AA03388",
        "mstrBlDt": "20190704",
        "consolidatedIndctr": "S",
        "prevDec": "N"
      },
      "prevRef": {
      },
      "locCstm": {
        "firstPrtOfEntry": "DEHAM",
        "destPrt": "INCCU1PLP1",
        "nxtPrtOfUnlading": "INCCU1",
        "typOfCrgo": "IM",
        "itemTyp": "OT",
        "crgoMvmt": "LC",
        "natrOfCrgo": "C",
        "splitIndctr": "N",
        "nmbrOfPkgs": 17.000000,
        "typOfPackage": "PKG"
      },
      "trnshpr": {
        "trnshprCd": "AAA25896Z0",
        "trnshprBond": "2001009852"
      },
      "trnsprtDoc": {
        "prtOfAcptCdd": "DEHAM",
        "prtOfReceiptCdd": "INCCU1",
        "cnsgnesName": "INDO TEEN CO",
        "cnsgneStreetAddress": "9 MITRA LANEKOLKATA-700007 INDIA PH.9831000786",
        "goodsDescAsPerBl": "4X20'GP S.T.C.DEFECTIVE TIN FREE STEEL COILS HS CODE:72105000   NET WEIGHT:101.523 KGS"
      },
      "trnsprtDocMsr": {
        "nmbrOfPkgs": 17,
        "typsOfPkgs": "PKG",
        "marksNoOnPkgs": "N/M",
        "grossWeight": 103223.000,
        "netWeight": 0.000,
        "grossVolume": 0.000,
        "invoiceValueOfCnsgmt": 0.00
      },
      "itemDtls": [{
        "crgoItemSeqNmbr": 1,
        "hsCd": "0507 90",
        "unoCd": "3077",
        "imdgCd": "3",
        "nmbrOfPkgs": 17,
        "typOfPkgs": "PKG"
      },
      {
        "crgoItemSeqNmbr": 2,
        "hsCd": "0507 [Ex",
        "unoCd": "3077",
        "imdgCd": "3",
        "nmbrOfPkgs": 10,
        "typOfPkgs": "PKG"
      }],
      "trnsprtEqmt": [{
        "eqmtSeqNo": 1,
        "eqmtId": "GLDU5395861",
        "eqmtTyp": "CN",
        "eqmtSize": "2200",
        "eqmtLoadStatus": "FCL",
        "eqmtSealNmbr": "EU16898250",
        "cntrAgntCd": "ADSPD9028J",
        "cntrWeight": 0.00,
        "totalNmbrOfPkgs": 5
      },
      {
        "eqmtSeqNo": 2,
        "eqmtId": "TCKU1362860",
        "eqmtTyp": "CN",
        "eqmtSize": "2200",
        "eqmtLoadStatus": "FCL",
        "eqmtSealNmbr": "EU16898247",
        "cntrAgntCd": "ADSPD9028J",
        "cntrWeight": 0.00,
        "totalNmbrOfPkgs": 4
      },
      {
        "eqmtSeqNo": 3,
        "eqmtId": "TCLU7234919",
        "eqmtTyp": "CN",
        "eqmtSize": "2200",
        "eqmtLoadStatus": "FCL",
        "eqmtSealNmbr": "EU16898245",
        "cntrAgntCd": "ADSPD9028J",
        "cntrWeight": 0.00,
        "totalNmbrOfPkgs": 4
      },
      {
        "eqmtSeqNo": 4,
        "eqmtId": "TRHU1592710",
        "eqmtTyp": "CN",
        "eqmtSize": "2200",
        "eqmtLoadStatus": "FCL",
        "eqmtSealNmbr": "EU16898246",
        "cntrAgntCd": "ADSPD9028J",
        "cntrWeight": 0.00,
        "totalNmbrOfPkgs": 4
      }],
      "itnry": [{
        "prtOfCallSeqNmbr": 1,
        "prtOfCallCdd": "DEHAM",
        "prtOfCallName": "HAMBURG",
        "nxtPrtOfCallCdd": "INCCU",
        "nxtPrtOfCallName": "KOLKATA"
      },
      {
        "prtOfCallSeqNmbr": 2,
        "prtOfCallCdd": "INCCU",
        "prtOfCallName": "KOLKATA",
        "nxtPrtOfCallCdd": "INCCU"
      }],
      "suplmntryDec": {
      },
      "houseCargoDec": [{
        "crgoDecRef": {
          "lineNo": 1,
          "mstrBlNo": "HBL001",
          "mstrBlDt": "20190704",
          "consolidatedIndctr": "S",
          "prevDec": "N"
        },
        "trnsprtDoc": [{
        }],
        "itemDtls": [{
          "eqmtSeqNo": 1,
          "eqmtId": "CNTRNO-1-1",
          "cntrWeight": 0.00,
          "totalNmbrOfPkgs": 0
        }],
        "trnsprtEqmt": [{
        }]
      },
      {
        "crgoDecRef": {
          "lineNo": 2,
          "mstrBlNo": "HBL002",
          "mstrBlDt": "20190704",
          "consolidatedIndctr": "S",
          "prevDec": "N"
        },
        "trnsprtDoc": [{
          "prtOfAcptCdd": "LKCMB",
          "cnsgnrsName": "ABCD",
          "cnsgnrStreetAddress": "COLOMBO",
          "cnsgnesName": "XXXXXCONSIGNEE"
        },
        {
          "prtOfAcptCdd": "SGSIN",
          "cnsgnrsName": "SINGAPORE CONSIGNOR",
          "cnsgnesName": "KOLKATA COSIGNEE"
        }],
        "itemDtls": [{
          "eqmtSeqNo": 2,
          "eqmtId": "CNTRNO-1-2",
          "cntrWeight": 0.00,
          "totalNmbrOfPkgs": 0
        }],
        "trnsprtEqmt": [{
        }]
      }]
    },
    {
      "MCRef": {
        "lineNo": 2,
        "mstrBlNo": "SCJUA37AA03391",
        "mstrBlDt": "20190704",
        "consolidatedIndctr": "S",
        "prevDec": "N"
      },
      "prevRef": {
      },
      "locCstm": {
        "firstPrtOfEntry": "DEHAM",
        "destPrt": "INCCU1CPL2",
        "nxtPrtOfUnlading": "INCCU1",
        "typOfCrgo": "IM",
        "itemTyp": "OT",
        "crgoMvmt": "LC",
        "natrOfCrgo": "C",
        "splitIndctr": "N",
        "nmbrOfPkgs": 10.000000,
        "typOfPackage": "PKG"
      },
      "trnshpr": {
      },
      "trnsprtDoc": {
        "prtOfAcptCdd": "DEHAM",
        "prtOfReceiptCdd": "INCCU1",
        "cnsgnesName": "INDO TEEN CO",
        "cnsgneStreetAddress": "9 MITRA LANE KOLKATA,700007INDIA PH.9831000786",
        "cnsgneCity": "KOLKATA",
        "cnsgneCntrySubDivName": "WEST BENGA",
        "cnsgneCntrySubDiv": "10",
        "cnsgnePstcd": "700007",
        "goodsDescAsPerBl": "2X20'GP S.T.C  DEFECTIVE TIN FREE STEEL COILS  HS CODE:72105000  NET WEIGHT:49692 KILOS"
      },
      "trnsprtDocMsr": {
        "nmbrOfPkgs": 10,
        "typsOfPkgs": "PKG",
        "marksNoOnPkgs": "N/M",
        "grossWeight": 50512.000,
        "netWeight": 0.000,
        "grossVolume": 0.000,
        "invoiceValueOfCnsgmt": 0.00
      },
      "itemDtls": [{
        "crgoItemSeqNmbr": 1,
        "hsCd": "07, 09 o",
        "nmbrOfPkgs": 10,
        "typOfPkgs": "PKG"
      },
      {
        "crgoItemSeqNmbr": 2,
        "hsCd": "0802, 08",
        "nmbrOfPkgs": 10,
        "typOfPkgs": "PKG"
      },
      {
        "crgoItemSeqNmbr": 3,
        "hsCd": "10",
        "nmbrOfPkgs": 10,
        "typOfPkgs": "PKG"
      }],
      "trnsprtEqmt": [{
        "eqmtSeqNo": 0,
        "eqmtId": "TCKU3438645",
        "eqmtTyp": "CN",
        "eqmtSize": "2200",
        "eqmtLoadStatus": "FCL",
        "eqmtSealNmbr": "EU16899299",
        "cntrAgntCd": "ADSPD9028J",
        "cntrWeight": 0.00,
        "totalNmbrOfPkgs": 5
      },
      {
        "eqmtSeqNo": 0,
        "eqmtId": "TLLU8090373",
        "eqmtTyp": "CN",
        "eqmtSize": "2200",
        "eqmtLoadStatus": "FCL",
        "eqmtSealNmbr": "EU16899293",
        "cntrAgntCd": "ADSPD9028J",
        "cntrWeight": 0.00,
        "totalNmbrOfPkgs": 5
      }],
      "itnry": [{
        "prtOfCallSeqNmbr": 1,
        "prtOfCallCdd": "DEHAM",
        "prtOfCallName": "HAMBURG",
        "nxtPrtOfCallCdd": "INCCU",
        "nxtPrtOfCallName": "KOLKATA"
      },
      {
        "prtOfCallSeqNmbr": 2,
        "prtOfCallCdd": "INCCU",
        "prtOfCallName": "KOLKATA",
        "nxtPrtOfCallCdd": "INCCU"
      }],
      "suplmntryDec": {
      },
      "houseCargoDec": [{
        "crgoDecRef": {
          "lineNo": 1,
          "mstrBlNo": "LINE-2-NO-1",
          "mstrBlDt": "20190729",
          "consolidatedIndctr": "S",
          "prevDec": "N"
        },
        "trnsprtDoc": [{
        }],
        "itemDtls": [{
          "eqmtSeqNo": 1,
          "eqmtId": "CNTRNO-2-1",
          "cntrWeight": 0.00,
          "totalNmbrOfPkgs": 0
        }],
        "trnsprtEqmt": [{
        }]
      },
      {
        "crgoDecRef": {
          "lineNo": 2,
          "mstrBlNo": "LINE-2-NO-2",
          "mstrBlDt": "20190730",
          "consolidatedIndctr": "S",
          "prevDec": "N"
        },
        "trnsprtDoc": [{
        }],
        "itemDtls": [{
          "eqmtSeqNo": 2,
          "eqmtId": "CNTRNO-2-2",
          "cntrWeight": 0.00,
          "totalNmbrOfPkgs": 0
        }],
        "trnsprtEqmt": [{
        }]
      }]
    }],
    "prsnOnBoard": [{
      "prsnOnBoardSeqNmbr": 1,
      "prsnId": {
        "prsnIdDocExpiryDt": "20000808",
        "prsnIdOrTravelDocIss": "US",
        "prsnIdOrTravelDocNmb": "S90006875",
        "prsnIdOrTravelDocTyp": "980"
      }
    },
    {
      "prsnOnBoardSeqNmbr": 2,
      "prsnId": {
        "prsnIdDocExpiryDt": "20010810",
        "prsnIdOrTravelDocIss": "TR",
        "prsnIdOrTravelDocNmb": "T3456875",
        "prsnIdOrTravelDocTyp": "980"
      }
    }],
    "voyageTransportEquipment": {
    },
    "tmSuprtDocs": {
    },
    "tmAdtnlDec": {
    }
  },
  "digSign": {
  }
}

ENDTEXT

Return m.cjson








Marco Plaza
@nfoxProject
 
Marco said something important, that I second. JSON was introduced to just be a text notation of Javascript memory objects. And everything in JS is an object. JS is no database language like VFP, so it can't really cope with SQL. It can do HTTP requests, and that's the basis of a few NoSQL databases to store JSON notation as "documents" in document collections and make them retrievable via a HTTP interface. It's not the only type of NoSQL and not the only reason for NoSQL databases, but enough of that.

JSON as text can of course also be stored in files, and Marco has written his library specifically for VFP to be able to also consume JSON into objects or cursors.

It's not a wrong idea to use it though you don't really do anything related to JS or the web with HTTP, just because JSON notation is shorter than XML, not as verbose. Also, it is a bit better than CSV, as it can represent something more complicated than a single table.

But Marco reminded me of the way to display DBFs "pivoted", single records appear as rows, if you don't BROWSE a workarea, but EDIT it. That's still actually a single record and not really pivoted data put into a table with two columns. Just note you can also get there if you browse a workarea. While the browse window has focus, pick the menu item "Edit" from the "View" menu, and the display changes.

If that is your original situation my code sample with the [tt]Insert Into authPrsn From Name loJSON.authPrsn[/tt] works, just end it with EDIT instead of BROWSE. I'm not sure, if that was all, since Marcos of course did more: He "flattened" the data of several JS (child) objects that reflect 1:1 that way as VFP (child) objects into a single record. (So no worries, Marcos, I recognize what you did there).

Then you actually don't need much special code, you already at least get all data into the object hierarchy VFP can also have - just like JS, via nfJSONread. Just as I already said. And then you can populate records from there. You even need less of a transformation or iteration of AMEMBERS to get out the single values. INSERT FROM NAME and GATHER NAME are your major tools to put object properties into table fields.

Bye, Olaf.

Olaf Doschke Software Engineering
 
Hi Olaf.. you're right, insert from name suffices if you don't need to flatten the structure.. just wanted to leave this sample to show the nfOpenJson alternative. I suggest deprecate the use of nfOpenJson in favor of this technique,
because I won't continue working with it given the fact that I already developed a soon-to-be-released set of new functions ( nfTools ) that will make this task and many alike easier.

















Marco Plaza
@nfoxProject
 
Thank you Olaf & Marco,

Thank you so much for your samples and Marco, really excited to see your new tool!

Now, I am half way through writing my code for json read and save to tables. However, I am a bit confused on one thing.
If you refer to the same json file we're discussing with, once I made an object out of it, I can traverse through each element hierarchically (thanks to Olaf's code). If I watch the object in 'Locals' window, I can see that 'ShipItnry' is shown an 'A'. But if I check VARTYPE it is 'O'. Whatever it may be, how can I retrieve the size of the array 'ShipItnry'?


Thanks,
Rajesh
 
Let me see...

Code:
"shipItnry": [{
        "shipItnrySeq": "-3"
      },
      {
        "shipItnrySeq": "-2"
      },
      {
        "shipItnrySeq": "-1",
        "prtOfCallCdd": "LKCMB"
      },
      {
        "shipItnrySeq": "0",
        "prtOfCallCdd": "INCCU1",
        "prtOfCallName": "KOLKAT"
      }]

From JSON notation perspective this is an array. And the array elements are objects. You get types A from the debugger, as that is an array, you get O from vartype, because when addressing an array name you actually address the first array element. You also get "A" from Type("shipItnry",l), look up the help topic of TYPE(). Vartype does NOT provide that.

And to get the length you have ALEN in Foxpro.

Bye, Olaf.



Olaf Doschke Software Engineering
 
More precisely TYPE("ojson.Master.voyagedtls.shipitnry",1) will be "A" and ALEN(ojson.Master.voyagedtls.shipitnry) tells you the array length.

Marco reads the elements in here with a FOR EACH loop, that means it doesn't matter how many elements there are in the array, this simply iterates each of them:
Code:
Select shipitnry

For Each oshipitnry In   ojson.Master.voyagedtls.shipitnry
  Append Blank
  Gather Name oshipitnry
Endfor
browse normal

So Marcos code is specific to the structure you gave, it makes use of known names, but it's not depending on knowing the count of elements.

The array elements (objects) read in as records then also have a count as end result, RECCOUNT("shipitnry").

Bye, Olaf.

Olaf Doschke Software Engineering
 
Olaf,

I am getting 'A' when I check through TYPE function with 1 as parameter. However, I was getting 'Not an array' message when tried ALEN on that. That's why I was confused. Now, I got it by using a macro substitution as in

? ALEN(mbr.&arr[2])

where mbr is my object and arr[2] is its 2nd element which is actually an array.

However, I think, I should try and go with that 'For each...' method mentioned by Marco.
I am checking with these options and suggestions.
Will get back here soon.

Rajesh
 
Are you working on yet other JSON? Because I was just using Marcos example, and there isn't an array containing a nested array, especially not shipitnry.

And closely watch, what I did. TYPE needs the name of the array variable (actually here an array property) as a string, ALEN() needs the array itself. Also, the fully qualified name of the array starts with the variable ojson, there is no array variable shipitnry, the array is a property of ojson.Master.voyagedtls, namely ojson.Master.voyagedtls.shipitnry. You can't shorten this name. You have the variable ojson, that has the JSON root object Master, which has a voyagedtls object, of which one property is an array shipitnry.

What nfreadJSON generates is 1:1 as nested as the object would be, if you'd unserialize it (that means load and set a variable to it) in JS.

Bye, Olaf.

Olaf Doschke Software Engineering
 
Olaf,

I successfully managed to write a program to retrieve data from the json object into its respective tables. The handling of array areas also appears to be okay now.

However, I have a problem. When nfJson object for a json is created, it rearranges the members in alphabetical order. This actually disturbs the hierarchy flow. For example, in the json I have members 'mcRef' and then 'houseCargoDec'. But when I look at the object, the 'houseCargoDec' comes first and then the 'mcRef'.

In fact, 'mcRef' contains master table data and 'houseCargoDec' contains data of a few child tables. I want to write a few field values of master into the child corresponding fields. But, now because this alphabetic order my child data is read first and I am stuck up.
I think Marco can help me to come out of this situation.

Dear Marco,
Could you just check this and help me out, please ?

Apart from this, things seem to be satisfactory and a BIG SALUTE to your nfJson, dear Marco!



Thanks in advance,
Rajesh
 
Amembers works that way, there and there also is no way around that when you start working on the unserielized object.

To get things in order of the JSON, you'd need to write code like nfJSONread on the parsing level.

Reading the properties, arrays, and child objects of the VFP ojson.Master object, there is no way to list the members in the chronology they were added to the object.

On the one side I see a helpful extension for your case may be a logging of the chronological order in which objects are added to VFPs ojson.Master.


Before I'd suggest MArco to add that, I'd argue it's not the job of such a library. You point out certain records need to come first because of relationships (You can't add detail data before head data). But you have the same problem in a database you'd process in ADBOBJECT() order. And the solution is to simply don't do it.

Just like a database isn't the list of tables in alphabetical order the ojson.Master object isn't the object tree in alphabetical and/or tree branch order, you read the child objects you need first, just like an SQL script adding a complex entity with a data hierarchy in 2 or more tables from head.

If you base your code on my iteration of AMEMBERS(), then why? Just like a specific database will always have a specific head data table, the ojso.Master has one specific child object that interests you first, then you're just as free to read that first like you can write SELECT * FROM headertable, no matter if there are tables starting with A-G before that.

Last5 not least, it would be very unusual, if traversing an object tree from root level to child nodes would confront you with a situation you come across some child/detail data before head data, as the object hierarchy also is only working from parent to child objects, head to details and that's very generally so, no matter what JSON you have. So, that may simply point out you did put data on the same tree depth level, that should perhaps rather be nested.

Because the main processing order of iterating AMEMBERS() is still the hierarchy levels of the object tree before it is about the alphabetical order of the nodes on the same level. If those levels represent the hierarchy level of tables, too, data on the same level should not have a relationship that needs to process a node before it's sibling nodes. The solution to that could actually be in the JSON generation process rather than the parsing / unserialization or the processing of the result VFP object tree.

Bye, Olaf.

Olaf Doschke Software Engineering
 
Marco / Olaf,

Please find pics to help with the alphabetical reordering issue in my message above.

Rajesh

json_and_object_views_pnuiq3.png
 
Olaf,

The object, in its creation level itself, was made to be rearranged in alphabetical order it appears. That's why I am looking forward to our Marco's advice/suggestion on this.

What I expect is that when the object is created from the json file, the order in which each member, sub-members etc appear in the json file should not be disturbed. When you explode the object, it should show the tree structure in the same order that is present in the json file.

Marco, could you help? Is there any way to achieve this?

Rajesh
 
You can't have that.

Neither the debugger nor IntelliSense will show you the members of an object in another order than alphabetical, nor does AMEMBER list members in the same sort order they were added.

But what hinders you to address the subobject how you want it? If you want to set a form position by setting top and left values, you just do that, you can change top before left and you don't need to read or set any other properties, do you?

Your code will be the sort order of how you process this object.

In a POS system where you want to iterate through receipts and then positions, you simply do that you nest two scan loops, the outer one iterates receipts and the inner one positions. You write specific code addressing the child nodes in the order you need.

Bye, Olaf.

Olaf Doschke Software Engineering
 
Olaf,

I just tried what you said. Just created an object and add properties 'ccc', 'bbb' & 'aaa' and when I accessed it using AMEMBERS, it is 'aaa', 'bbb' & 'ccc'. Yes, Olaf, I am forgetting that plan!

Let me think of an alternative to solve the problem.

I have the order of members that I want in a control table. Maybe, after retrieving the sub members of a member from the object, into an array using 'AMEMBERS', I can probably sort it again according to the order in the table and then can start working on them one by one. This is one possible way, I believe. Let me try that.

Whatever may be the way, I have to succeed!

Thanks
Rajesh
 
Dear Marco,

Just to make the things clear! I posted it like your nfJson disturbs the actual order of members it reads during the creation of the object. But, Olaf made it clear that AMEMBERS gives you the member list in alphabetical order only. So, I am really sorry about my statement about your nfJson.

That library is the key for my program and salutes to nfJson once again!

Now, I am trying to figure out a way to solve the problem.
Will get back here once I find something.

Thanks,
Rajesh
 
I have the order of members that I want in a control table

That's fine, then you can do that. Something like

Code:
...
ojson= nfreadJSON(...)
...
SELECT controltable
SCAN
   lcMember = controltable.objectname
   * do soemthing WITH ojson.master.&lcMember
ENDSCAN

Bye, Olaf.

Olaf Doschke Software Engineering
 
Hello Rajesh don't worry. Your question/requirement is a very common one , and Olaf already gave you the reason why it happens and why you don't need to have the members in a particular order since your driving program dictates the order in wich elements are processed.

Important note: we should not confuse the Json representation of the object ( the json document ) with the object loaded in memory. This always arise when we want to compare json documents visually or using diff tools, discovering it is not possible when json is generated by different tools; that's where object schemas come to play, but it will add a penalty in speed object serialization. I don't want to enter in much details, but nfTools will support that option
by inferring the object schema from json.

Finally, you might find useful Microsoft's Rest Api guide ( ):

Clients MUST NOT rely on the order in which data appears in JSON service responses. For example, clients SHOULD be resilient to the reordering of fields within a JSON object. When supported by the service, clients MAY request that data be returned in a specific order. For example, services MAY support the use of the $orderBy querystring parameter to specify the order of elements within a JSON array. Services MAY also explicitly specify the ordering of some elements as part of the service contract. For example, a service MAY always return a JSON object's "type" information as the first field in an object to simplify response parsing on the client. Clients MAY rely on ordering behavior explicitly identified by the service.



Marco Plaza
@nfoxProject
 
And perhaps the most prominent case against relying on the order of properties in JSON is how JS itself handlöes this, once you write

let x = { "zzz": 42, "mmm": 21, "aaa": 0 }

in the console of your Browser (press F12 right now) and then use intellisense, the properties also appear sorted and interleaved with standard properties every JS object has (that compares to VFPs custom class already having some methods and properties by default).

js_intellsense_zrrbhg.jpg


And that means, you mainly know the child object names when you'd do the parsing yourself. Marco could offer hoiok methods (something like afterparseobject, afterparsearray) that he calls with the name or object or array itself, that is just added to ojson.master and you could work with that.

I don't know if Marco would be happy with such a code design.

Bye, Olaf.


Olaf Doschke Software Engineering
 
Olaf / Marco,

The hierarchy order problem also is solved now!
I am getting the data into their respective tables.

Thank you so much for all your help!
Rajesh
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top