3

I can't figure out how to remove null values (and corresponding keys) from the output JSON.

Using JSON GENERATE, I am creating JSON output and in output I am getting \U0000 as null.

I want to identify and remove null values and keys from the JSON.

Cobol version - 6.1.0

I am generating a file with PIC X(5000). Tried INSPECT and other statements but no luck :(

For example :

    {
        "Item": "A",
        "Price": 12.23,
        "Qty": 123
      },
      {
        "Item": "B",
        "Price": \u000,
        "Qty": 234
      },
      {
        "Item": "C",
        "Price": 23.2,
        "Qty": \u0000
      }

In output I want:

    {
        "Item": "A",
        "Price": 12.23,
        "Qty": 123
      },
      {
        "Item": "B",
        "Qty": 234
      },
      {
        "Item": "C",
        "Price": 23.2,
      }

Approach 1:

  • created JSON using JSON GENERATE command and defined output file in PIC X(50000).
  • after converting to UTF-8 trying to use INSPECT to find the '\U000' using hex value but there is no effect on UTF8 arguments and not able to search '\U000' values.
perform varying utf-8-pos from 1 by 1 
   until utf-8-pos = utf-8-end 
   EVAUATE TRUE 
    WHEN JSONOUT(1:utf-8-pos) = X'5C'    *> first finding a "\" value in o/p
      perform varying utf-8-pos from 1 by 1
          until JSONOUT(1:utf-8-pos)  = x'22'   *> second finding a end position string " as X'22' 
               move JSONOUT(1: utf-8-end - utf-8-pos) to JSONOUT     *> skip the position of null
      end-perform
    WHEN JSONOUT(1:utf-8-pos) NOT= X'5C'
      continue
    WHEN OTHER
      continue 
   END-EVALUATE
end-perform     

Approach 2:

  • Convert the item to UTF-16 in a national data item by using NATIONAL-OF function.
  • using INSPECT, EVALUATE OR PERFORM to find '\U000' using hex value N'005C'. but not able to find the correct position of '\u000' also tried NX'005C' to find but no luck.
IDENTIFICATION DIVISION.
PROGRAM-ID.   JSONTEST.

ENVIRONMENT DIVISION.
CONFIGURATION SECTION.

SOURCE-COMPUTER. IBM-370-158.

DATA DIVISION.

WORKING-STORAGE SECTION.

  01 root.
   05 header.
     10 systemId       PIC X(10).
     10 timestamp      PIC X(30).
   05 payload.
     10 customerid         PIC X(10).
  
  77 Msglength   PIC 9(05).
  77 utf-8-pos   PIC 9(05).
  77 utf-8-end   PIC 9(05).

01 jsonout    PIC X(30000).

PROCEDURE DIVISION.

MAIN SECTION.

    MOVE "2012-12-18T12:43:37.464Z"   to   timestamp
    MOVE LOW-VALUES                   to   customerid
    JSON GENERATE jsonout
         FROM root
       COUNT IN Msglength
       NAME  OF root is OMITTED 
                systemId IS 'id'
      ON EXCEPTION
         DISPLAY 'JSON EXCEPTION'
         STOP RUN
   END-JSON
   
   DISPLAY jsonout (1:Msglength)
   
   PERFORM skipnull.

MAIN-EXIT.
 EXIT.


Skipnull SECTION.

perform varying utf-8-pos from 1 by 1 
   until utf-8-pos = utf-8-end 
   EVALUATE TRUE 
    WHEN JSONOUT(1:utf-8-pos) = X'5C' *> first finding a "\" value in o/p
      perform varying utf-8-pos from 1 by 1
          until JSONOUT(1:utf-8-pos)  = x'22'   *> second finding a end position string " as X'22' 
               move JSONOUT(1: utf-8-end - utf-8-pos) to JSONOUT   *> skip the position of null
      end-perform
    WHEN JSONOUT(1:utf-8-pos) NOT= X'5C'
      continue
    WHEN OTHER
      continue 
   END-EVALUATE
end-perform.

Skipnull-exit.
EXIT.

sample output : As we don't have any value to fill for customer id so in o/p results we are getting :

{"header" : {
   "timestamp" : "2012-12-18T12:43:37.464Z",
   "customerid" : "\u0000\u0000\u00000"   }
}

in result I want to skip customerid from the o/p. I want to skip both object:Name from the o/p file.

Simon Sobisch
  • 6,263
  • 1
  • 18
  • 38
  • 2
    Add your COBOL code to the question. – Gilbert Le Blanc Dec 17 '20 at 16:16
  • I can't share the code but I can share the approaches that I tried: – Sandhya Thakur Dec 18 '20 at 07:56
  • perform varying utf-8-pos from 1 by 1 until utf-8-pos = utf-8-end EVAUATE TRUE WHEN JSONOUT(1:utf-8-pos) = X'5C' ==== first finding a "\" value in o/p perform varying utf-8-pos from 1 by 1 until JSONOUT(1:utf-8-pos) = x'22' ==== second finding a end position string " as X'22' move JSONOUT(1: utf-8-end - utf-8-pos) to JSONOUT ===== skip the position of null end-perform WHEN JSONOUT(1:utf-8-pos) NOT= X'5C' continue WHEN OTHER continue END-EVALUATE end-perform @GilbertLeBlanc – Sandhya Thakur Dec 18 '20 at 09:05
  • 1
    I don't have a COBOL compiler handy, but I think that you need a perform loop. Look for the string "\u000" with the outer loop. When you find the string, look backward for the second double quote mark. You now have the beginning and the end of the null string. Either remove the characters or replace the characters with spaces. Removing the characters would be more difficult. You'd have to copy the preceding characters and following characters to another x(5000) field, then copy the whole block back. – Gilbert Le Blanc Dec 18 '20 at 11:33
  • @SimonSobisch I have posted the sample code will it be helpful for you. – Sandhya Thakur Dec 18 '20 at 12:15
  • @GilbertLeBlanc.. The issue is here the JSON output generated in encoded UTF-8 form so while using reference modification for checking character values like for X'5C' hex value of '\' then there is no effect on utf-8 arguments and not able to find that value. – Sandhya Thakur Dec 18 '20 at 12:19
  • 1
    UTF-8 uses exactly one byte for both `\` and for `0` - so just iterating about `jsonout` until you find the ascii-value `"\u000` should be enough, no need for an extra hex-check at all... or we all don't get the problem then you'd have to upload the sample file... – Simon Sobisch Dec 19 '20 at 16:41
  • {"header" : { "timestamp" : "2012-12-18T12:43:37.464Z", {"payload": "customerid" : "\u0000\u0000\u00000" } }} Sample o/p file and the requirement is want to remove customerid which is filled with \u000 values. want to remove both field and value from the o/p file. @SimonSobisch – Sandhya Thakur Dec 21 '20 at 06:30

2 Answers2

3

Since Enterprise COBOL's JSON GENERATE is an all-in-one-go command I don't think there's an easy way to do this in V6.1.

Just to give you something to look forward to: Enterprise-COBOL 6.3 offers an extended SUPPRESS-clause that does just what you need:

JSON GENERATE JSONOUT FROM MYDATA COUNT JSONLEN                
     SUPPRESS WHEN ZERO                                           
     ON EXCEPTION DISPLAY 'ERROR JSON-CODE: ' JSON-CODE        
     NOT ON EXCEPTION DISPLAY 'JSON GENERATED - LEN=' JSONLEN  

You can also suppress WHEN SPACES, WHEN LOW-VALUE or WHEN HIGH-VALUE. You can also limit suppression to certain fields:

SUPPRESS Price WHEN ZERO
         Qty   WHEN ZERO

Unfortunately this feature hasn't been backported to 6.1 yet (it's been added to 6.2 with the December 2020 PTF) and I don't know whether it will be...

piet.t
  • 11,718
  • 21
  • 43
  • 52
  • Yes there is a restriction of using all the features of JSON GENERATE in V6.1 that is the reason I am trying above mentioned approaches like inspect to remove null after reading lot of information about UTF-8 but seems I am missing something. – Sandhya Thakur Dec 18 '20 at 08:23
1

I don't know anything about cobol but I was need the same thing in javascript, so I will share my javascript function for you. If you can translate this to cobol maybe it will help to you.

function clearMyJson(obj) {
    for (var i in obj) {
        if ($.isArray(obj[i]))
            if (obj[i].length == 0) //remove empty arrays
                delete obj[i];
            else
                clearMyJson(obj[i]);  //calling function for clear the array
        else if ($.isPlainObject(obj[i]))
            if ((obj[i] == null || obj[i] == "")) // delete property if its null or empty
                delete obj[i];
            else
                clearMyJson(obj[i]); //calling function for clear the object 
    }
}
cbalakus
  • 620
  • 7
  • 15