1

I need to parse a json file into a javascript object. I'm using GCC (Closure Compiler) which might mangle my object names, so I need to refer to the json keys as strings when importing or exporting the json file.

i.e. importing:

var jsonobj = JSON.parse(json_object_text);
myobj.member1 = jsonobj['Key 1'];
myobj.member2 = jsonobj['Key 2'];

and exporting:

jsonobj['Key 1'] = myobj.member1;
jsonobj['Key 2'] = myobj.member2;
var json_object_text = JSON.stringify(jsonobj);

But doing that is tedious. And I would like to only define the keys as text strings once.

So I tried to define a constant object which is kind of mapping from javascript object to the json schema.

// Schema definition for import/export of confc.json.
/** @const */ var dbs = {
    $schema: '$schema',
    $seq: '$seq',
    channel: {
      key: 'chan',
      id: 'id',
      name: 'txt',
      value: 'val'
    }
}

But then I still had to do a tedious import/export function:

    export_db: function (db) {
      return db && {
        [dbs.$schema]: db.$schema,
        [dbs.$seq]: db.$seq,
        [dbs.channel.key]: db.channel.map(function (e, i) {
          var s = dbs.channel; // schema object
          return {
            [s.id]: util.toInt(e.id),
            [s.name]: e.name,
            [s.value]: e.value
          };
        }),
    import_db: function (js) {
      js = js || {};
      // wrapper for .map() function which works if array is undefined.
      function dbmap(arr_in, func) {
        arr_in = arr_in || [];
        return arr_in.map(func);
      }
      return {
        $schema: js[dbs.$schema],
        $seq: js[dbs.$seq],
        channel: dbmap(js[dbs.channel.key], function (e, i) {
          var s = dbs.channel;
          return {
            id: e[s.id],
            name: e[s.name],
            value: e[s.value]
          };
        }),

This seems to work OK, but would someone please show me a cleaner way to do this?

I would like to use an object prototype/constructor like in the examples given here. But I don't see any examples that take into account how GCC might mangle the objects member names. Also I have nested objects (no functions, just text and numbers).

phatpaul
  • 166
  • 7

2 Answers2

1

If the data source is external, or if you need to share the data externally, the way that Closure supports this via externs and @export annotations. User contributed externs are a great source for examples.

It might look like this, depending on your environment;

// externs/config.js

/**
 * @typedef {{
 *   foo: (string|undefined),
 *   [...]
 * }}
 */
Bar.Config;

/**
 * @typedef {{
 *   bar: (string|undefined),
 *   [...]
 * }}
 */
Bar.Output;

// main.js

/**
 * @param {Bar.Config} config 
 * @return {Bar.Output}
 */
const bar = function(config) {
//  [...]
  return output;
};

Graham P Heath
  • 7,009
  • 3
  • 31
  • 45
  • Thanks, I'm aware of externs. But if I extern the entire schema of my json file, it forces GCC not to rename any of the object members within my entire code. I want to allow GCC to shorten the names within my code, but just import/export using the full string names. – phatpaul Oct 02 '19 at 20:22
0

JSON is inherently already in object format (JSON = JavaScript Object Notation).

var jsonobj = JSON.parse(json_object_text) should be all you need to access the object you just created called jsonobj. Any members of that object are accessible just as if you had defined them in an constructor or anywhere else. Is there a reason you're remapping it to a different object?

mrflagio
  • 13
  • 1
  • 3
  • I'm taking advantage of Google-Closure-Compiler's ability to optimize my code which includes renaming variables,functions,object members, etc. That works great until you have to interface with external code or JSON objects. GCC might rename myobj.member1 to a.b. But the external json file retains it's original keys 'Key 1', hence the mapping. Please see [GCC documentation](https://developers.google.com/closure/compiler/docs/compilation_levels) – phatpaul Oct 01 '19 at 21:13