openedgeprogress-4gl

OpenEdge ABL JSON to temp table: READ-JSON


How can I READ-JSON this (below) into temp table :

{
  "args": {
  },
  "data": "{\"name\":\"morpheus11\",\"job\":\"leader1221\"}",
  "files": {
  },
  "form": {
  },
  "headers": {
    "Accept": "application\/json",
    "Content-Length": "40",
    "Content-Type": "application\/json",
    "Host": "httpbin.org",
    "User-Agent": "OpenEdge-HttpClient\/0.4.0 (UNIX\/64) OpenEdge\/99.2.99.0.9999 Lib-ABLSockets\/0.5.0",
    "X-Amzn-Trace-Id": "Root=1-9999998e-0e281713363302e331999999"
  },
  "json": {
    "job": "leader1221",
    "name": "morpheus11"
  },
  "origin": "888.53.150.88",
  "url": "https:\/\/httpbin.org\/post"
}

This is what I have written so far. Right now the export stream dOut1 does not produce anything. My guess is that I don't have all the table specify... DO I need to define all json node like: Args, Data, Files, Headers, Origin and URL? Thank you for your help

  def temp-table tt serialize-name 'json'
   field job  as char 
   field name as char.
  def dataset args for tt.

  def var dURL         as char          no-undo init "https://httpbin.org/post".
  def var dRequest     as IHttpRequest  no-undo.
  def var dResponse    as IHttpResponse no-undo.
  def var dClient      as IHttpClient   no-undo.
  def var dRequestResp as longchar      no-undo.  
  def var dJson        as JsonObject    no-undo. /* used by outbound Json and the return inbound Json */
  
  dClient = ClientBuilder:Build():Client.
  dJson   = new JsonObject() .
  dJson:Add("name","morpheus11").
  dJson:Add("job","leader1221").

  dRequest  = RequestBuilder:Post(dURL,dJson)
                    :ContentType('application/json')
                    :AcceptJson()
                    :Request.
  dResponse = dClient:Execute(dRequest).
  
  if dResponse:StatusCode <> 200 then do:
    message subst("dResponse:StatusCode = &1", dResponse:StatusCode).
  end. 
  else do:
    dJson = cast(dResponse:Entity, JsonObject).
    dJson:Write(dRequestResp, true).
    
    dataset args:read-json("longchar",dRequestResp).
    for each tt on error undo, return error on stop undo, return error:
      export stream dOut1 delimiter "|"
        tt.
    end. 
    output stream dOut1 close.
  end.

Thank you


Solution

  • The JSON does not match a ProDataset. ProDatasets are represented by JSON objects with a nested JSON array per temp-table.

    But you can read the "json" object directly into the temp-table's tt default-buffer:

    dJson = cast(dResponse:Entity, JsonObject).
    dJson = dJson:GetJsonObject ("json") .
    dJson:Write(dRequestResp, true).
    buffer tt:read-json("longchar",dRequestResp).
    

    and a further optimization: No need to use the longchar as an intermediate:

    dJson = cast(dResponse:Entity, JsonObject).
    dJson = dJson:GetJsonObject ("json") .
    buffer tt:read-json("JsonObject", dJson).
    

    Here's my comlete sample:

    /*------------------------------------------------------------------------
        File        : json.p
        Purpose     :
    
        Syntax      :
    
        Description :
    
        Author(s)   : mikef
        Created     : Sun Jan 07 16:08:47 CET 2024
        Notes       :
    
    https://stackoverflow.com/questions/77766521/openedge-abl-json-to-temp-table-read-json
    
      ----------------------------------------------------------------------*/
    
    /* ***************************  Definitions  ************************** */
    
    BLOCK-LEVEL ON ERROR UNDO, THROW.
    
    USING Consultingwerk.Util.* FROM PROPATH.
    using Progress.Json.ObjectModel.* from propath.
    using OpenEdge.Net.HTTP.* from propath.
    
    /* ***************************  Main Block  *************************** */
    
      def temp-table tt serialize-name 'json'
       field job  as char
       field name as char.
      def dataset args for tt.
    
      def var dURL         as char          no-undo init "https://httpbin.org/post".
      def var dRequest     as IHttpRequest  no-undo.
      def var dResponse    as IHttpResponse no-undo.
      def var dClient      as IHttpClient   no-undo.
      def var dRequestResp as longchar      no-undo.
      def var dJson        as JsonObject    no-undo. /* used by outbound Json and the return inbound Json */
    
      define stream dOut1 .
    
      OUTPUT STREAM dOut1 TO "Test/output.txt" .
    
      dClient = ClientBuilder:Build():Client.
      dJson   = new JsonObject() .
      dJson:Add("name","morpheus11").
      dJson:Add("job","leader1221").
    
      dRequest  = RequestBuilder:Post(dURL,dJson)
                        :ContentType('application/json')
                        :AcceptJson()
                        :Request.
      dResponse = dClient:Execute(dRequest).
    
      if dResponse:StatusCode <> 200 then do:
        message subst("dResponse:StatusCode = &1", dResponse:StatusCode).
      end.
      else do:
        dJson = cast(dResponse:Entity, JsonObject).
    
        dJson = dJson:GetJsonObject ("json") .
    
    //    dJson:Write(dRequestResp, true).
    
        BUFFER tt:read-json("JsonObject", dJson).
        for each tt on error undo, return error on stop undo, return error:
    
    //BufferHelper:ShowBuffer(BUFFER tt:HANDLE).
    
          export stream dOut1 delimiter "|"
            tt.
        end.
        output stream dOut1 close.
      end.
    

    and the output file:

    "leader1221"|"morpheus11"