New feature: JSON parsing!

Apparently, all the cool kids these days are saving and loading all their data as JSON…

So, not wanting to seem like an old fuddy-duddy, I’ve added some classes to parse and write JSON data. It’s in (unsurprisingly) a class called “JSON”.

I’d appreciate any seasoned JSON users letting me know their opinions/gripes/requests!

Ooh, baby!

Any plans to go a little further and support YAML as well? nudge, nudge.

Good move, Jules!

Oh no, have all the trendy kids moved on from JSON to YAML already!?

2 Likes

Is this faster than XML ?

Oh no, have all the trendy kids moved on from JSON to YAML already!?

NO, JSON is a proper subset of YAML and as such will always be good to go! Plus, there aren’t official implementations for e.g. Javascript yet. However, there will be, and since it’s completely compatible…

You’re hitting JSON at exactly the right time (well :smiley: perhaps a bit late), at the sweet spot for this technology. YAML, you’d be an early adopter.

For me, the big advantage of YAML over HSOB is when you’re cutting and pasting records into emails and such, or sending a stream of records through a socket - the fact that it is even more minimal and readable than JSON is another plus.

Is this faster than XML?

At the top level, both XML and JSON parsers are the same O() but in practice JSON parsers always seem to beat comparable XML parsers by a healthy margin and in some cases by over an order of magnitude, if you are validating the XML against a grammar, schema, DTD or whatever the name is (I’ve tried to repress my XML experiences).

There are many reasons why.

The first is simply that JSON documents are always substantially shorter than XML documents, so there are fewer characters to process.

The second is that XML is simply more complex! Clearly, validating a document against a grammar is a hugely time-consuming process, and one can imagine pathological cases with complex grammars… so let’s simply talk about non-validating XML parsers… but even then there are just more “moving parts”, more states in our state machine.

Finally, the data structures that represent XML consume more memory than the data structures that represent JSON. In most newer programming languages (Python, Javascript, etc), JSON objects directly correspond to the native “array” and “associative dictionary” types, so there is simply no need to create a new data structure at all.

In older languages like C++ and Java, there is no specific canonical/“native” associative dictionary(*), so you have to choose one of the many available classes to do this, but it’ll still be something small and fast.

Either way, you end up with arrays and associative dictionaries, things that your language has numerous tools to deal with already.

An XML object is not so simple. It has properties and it contains other tags - or it might be CDATA! So you need some special purpose XML data structure to represent this - a more complex data structure that will occupy more space and resist optimization.

But what about validation with a grammar, schema or DTD? Well, you just throw that in the bin completely - it was a worthless idea. You were always validating the data in your program anyway, making sure ages were positive and IDs existed in your database.

So now you parse any old crap that’s valid JSON, do the work if you have the data fields you need or complain if you don’t, and simply ignore any fields you don’t recognize (which is great for forward and backward compatibility).

OK, but what if you need a data language? Well, XML didn’t provide you with one, did it? :slight_smile: I use Google’s free, open source Protocol Buffers for that purpose. It’s a pretty big hammer in some ways, but it generates tight code and a lot of very fancy features.

Protocol buffers aren’t directly JSON, but they have just the same structure, so writing a wrapper to and from JSON (in fact, YAML) turned out to be a pleasant couple of hours’ work with no issues (given a vast amount of work and a lot of hair-pulling previously on all these topics :-D).

(* - actually, I’m thinking this is no longer true in recent versions of Java…)

Great analysis Mr. Swirly!

What would you think of using JSON to externally define a user interface? For example the placement and appearance of controls and their parents?

What would you think of using JSON to externally define a user interface? For example the placement and appearance of controls and their parents?

Oh, you mean, for skinning? Well, that’s exactly what I’m doing now - well, prepared to do anyway, I ended up hard-coding the descriptions in my final rush on this version 0.8… it seems work pretty well, except I haven’t at all exercised it in anger.

Are you thinking of having your users do it? In those cases, it really helps if you have a data definition language - because then you can actually select from only the field names valid in the current context and not just have a free-form text file or text area.

But is a free-form text area so bad? Frankly, most people are smart enough to just write the JSON and be done with it, particularly if they can see a report on unknown names afterward.

Yes, and I’m ok with hand-editing of text files.

It’s worked great for me in the past, go for it!

Good error reporting is a useful feature here…

Wow, great Jules. I was just gearing up to needing a JSON parser as finally my PHP life and my C++ life are starting to converge once more.

I’m going to have to plus one the YAML request, but JSON is pretty damn helpful regardless. :slight_smile:

Hmm - reading some YAML info, it does look like a really good format, but waaay more complicated than JSON to parse! I wrote the JSON parser in a few hours, but I think a YAML one would take considerably longer!

It’s a cool format though, next time I fancy a bit of parser-writing, I’ll have a go!

My theory is that long before you have to deal with YAML, you’ll have a solid mechanism to share embeddings of third-party libraries, so you can simply “point” to some well-known third-party library and a little of your wrapper code to get it into some Juce-y format.

Writing parsers is too much fun, because it’s just the right amount of easy and it’s a nice, abstract world…

Can I request that ValueTrees can go to and from json please? In the same way they go to and from streams and XML?

Bruce

[quote=“Bruce Wheaton”]Can I request that ValueTrees can go to and from json please? In the same way they go to and from streams and XML?

Bruce[/quote]

Indeed. Annoyingly, XML and ValueTrees don’t quite map onto a var/JSON structure, but I’ll find a way to bodge it!

Having done this before (damn, I keep chiming in with that - I feel like someone’s grandfather! - but I guess I’ve been doing this for over three decades. :-/ *(#$#)

There are minor difficulties in both directions - how do you represent arrays in XML? How do you represent CDATA and atrributes in JSON?

I created two “special” JSON field names: &attributes and &cdata (actually, I used .attributes and .cdata but it occurs to me this time that & is better as it should never appear in an XML attribute) and simply park attributes or cdata in associative array fields of this name.

The array issue I didn’t do a great job on, simply creating special tags and <0>, <1>, <2> in the XML. In hindsight, perhaps tags like <_>, <_0>, <_1> might be more obvious and less prone to collisions (is _ legal as a leading character in tags?!)

I’ll be interested to see what you come up with!

Some of those my not affect me - sounds more like XML <> JSON than ValueTree.

Apart from persistence and default settings, I’m interested in getting and setting individual values or sets of values from arbitrary external sources.

Bruce

ValueTree is somewhat less gnarly than XML, yes, so it should be easier!

If Jules doesn’t knock it out sooner, I’ll do it later, I need it “eventually” (but not this month).

This might be a start…(I’m using ValueTree’s because of the listener functionality), and then when I need to serialize it I just make it a var then send it to the JSON::toString() function

	var valueTreeToVar(const ValueTree &vt)
	{
		
		DynamicObject* const resultObject = new DynamicObject();
		var result = resultObject;
		NamedValueSet& resultProperties = resultObject->getProperties();
		for (int i=0;i<vt.getNumProperties();i++)
		{	
			Identifier name(vt.getPropertyName(i));
			resultProperties.set(name,vt.getProperty(name));
		}
		for (int i=0;i<vt.getNumChildren();i++)
		{
			result.append(valueTreeToVar(vt.getChild(i)));
		}
		return result;
	}

ValueTree varToValueTree(const var &varresult,Identifier name)
	{
		ValueTree vt(name);
		if (varresult.isObject())
		{
			DynamicObject* object=varresult.getDynamicObject();
			NamedValueSet& props=object->getProperties();
			for (int i=0;i<props.size();i++)
				vt.setProperty(props.getName(i), props.getValueAt(i), NULL);
		}
		else {
			jassertfalse;
		}
		
		return vt;
	}