Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Parsing json, key without quotes

I am getting response from server where the key is not with quotes. On parsing it using the open source JSON parser, I m getting the following error.

-JSONValue failed. Error is: Unrecognised leading character

& if I add double quotes (") to the key manually, I get what I want. What do I do?

Thanx a lot in advance.

EDIT: please see the following, if its correct

{

    status: 200,
    statusMsg: "Success",
    statusInfo: {
        custType: "Active",
        custCount: 600,
        custAccount: "Premium" 
    },
    custInfo: {
        custName: "ABC",
        custCode: "CU102",
        custNumber: 9281 
    },
    errors: [

    ]

}
like image 408
sole007 Avatar asked Dec 08 '10 10:12

sole007


3 Answers

I wanted the equivalent of Python's ast.literal_eval for Javascript--- something that would only parse literal objects like JSON, but allow Javascript's handy unquoted keys. (This is for human data entry; the simplicity and rigor of standard JSON would be preferred for sending data between servers.)

This is also what the original poster wanted, so I'll put my solution here. I used the Esprima library to build an abstract syntax tree and then I converted the tree into objects, like this:

function literal_eval(object_str) {
    var ast = esprima.parse("var dummy = " + object_str);

    if (ast.body.length != 1  ||  ast.body[0].type != "ExpressionStatement")
        throw new Error("not a single statement");

    return jsAstToLiteralObject(ast.body[0].expression.right);
}

function jsAstToLiteralObject(ast) {
    if (ast.type == "Literal")
        return ast.value;

    else if (ast.type == "ArrayExpression") {
        var out = [];
        for (var i in ast.elements)
            out.push(jsAstToLiteralObject(ast.elements[i]));
        return out;
    }

    else if (ast.type == "ObjectExpression") {
        var out = {};
        for (var k in ast.properties) {
            var key;
            if (ast.properties[k].type == "Property"  &&
                ast.properties[k].key.type == "Literal"  &&
                typeof ast.properties[k].key.value == "string")
                key = ast.properties[k].key.value;

            else if (ast.properties[k].type == "Property"  &&
                     ast.properties[k].key.type == "Identifier")
                key = ast.properties[k].key.name;

            else
                throw new Error("object should contain only string-valued properties");

            var value = jsAstToLiteralObject(ast.properties[k].value);
            out[key] = value;
        }
        return out;
    }

    else
        throw new Error("not a literal expression");
}

The "var dummy = " + is needed so that Esprima interprets an initial { character as the beginning of an object expression, rather than a code block.

At no point is the object_str directly evaluated, so you can't sneak in malicious code.

As a side benefit, users can also include comments in the object_str.

For this kind of problem, YAML is also worth considering. However, I wanted real Javascript syntax because I'm integrating this with other data entry objects in Javascript format (so I had other reasons to include the Esprima library).

like image 120
Jim Pivarski Avatar answered Nov 12 '22 16:11

Jim Pivarski


I originally put this in as a comment, but I think it counts as an answer albeit not necessarily a very helpful one.

The example you posted is not JSON. Check the JSON syntax. The only unquoted entities allowed except for numbers, objects and arrays are null, true, false. So the keys in your example are invalid and so are the non numeric values.

So you really should raise a defect report with the service provider (if they are claiming that they are producing JSON, rather than some modified version of it).

If they refuse to fix the problem, you'll need to write a nearly-JSON parser or find an existing one that is less strict about syntax.

like image 5
JeremyP Avatar answered Nov 12 '22 17:11

JeremyP


Update for Swift 4

I was looking for a way to parse JSON that has keys without quotes, and I finally found a simple way to do it by using regex. This is the regex needed to match the keys without quotes:

(\\\"(.*?)\\\"|(\\w+))(\\s*:\\s*(\\\".*?\\\"|.))

To add the quotes, replace with \"$2$3\"$4.

Example:

let string = "{ custType: \"Active\", custAccount: \"Premium\" }"
let regex = string.replacingOccurrences(of: "(\\\"(.*?)\\\"|(\\w+))(\\s*:\\s*(\\\".*?\\\"|.))", with: "\"$2$3\"$4", options: .regularExpression)
print(regex)

Output:

{ "custType": "Active", "custAccount": "Premium" }
like image 4
Ibrahim Avatar answered Nov 12 '22 15:11

Ibrahim