I am using Json.NET's ability to convert XML to JSON and it works pretty well. I say "pretty well" because it will map empty XML nodes to null
instead of {}
(empty JSON object). However, because this web-services result drives a knockout.js binding, I need empty XML elements to map to {}
in order to maintain the binding structure1.
The current approach looks like:
// Json.NET XML->JSON
// Can I specify any custom converters for this?
var json = Newtonsoft.Json.JsonConvert.SerializeXNode(xDoc);
// JSON->JObject
var jObject = Newtonsoft.Json.JsonConvert.DeserializeObject(json);
// Update all `null` values to `{}`
// This "works reliably" because XML properties can never be null, but is
// hackish in its own right.
ConvertNullToEmptyObject(jObject as JContainer);
// And we're back at JSON, but I'd like to avoid such
// a complicated XML->JSON->JObject(Fixup)->JSON route.
// Performance isn't an issue, but it just feels dirty.
var finalJson = Newtonsoft.Json.JsonConvert.SerializeObject(jObject);
So then (the questions!);
Notes:
XElement->JObject
conversion function (using the same rules, or even code, as Json.NET), but I would like to re-use library support if possible. If you think I should just do this to start with, leave a comment saying so.1 The general approach of knockout<-JSON<-WS(XML)->JSON->knockout
works quite well. This issue here is that standard knockout.js template bindings (in conjunction with ko.mapping
) will not "auto-vivify" the structure even though binding to nonexistent properties (within an existing structure) works well.
If you have a better answer, write it. Accepted answers can be changed.
Well, I'm going to say this is "not reasonably possible" with Json.NET.
I cracked open Json.NET's XmlNodeConverter and it only interfaces externally with JsonReader and JsonWriter.
While it would likely be possible to write a JObjectReader and a JObjectWriter, this would involve more work than I am currently willing to invest.
Alternatively, I could copy all of the XmlNodeConverter code (most of it is private/internal) and modify it per my requirements - but this sort of copy'n'paste mass-duplication rubs me wrong.
What I have now works well enough, even if does seem wasteful.