jsuddsjr
jsuddsjr

Reputation: 550

Json.NET, can SerializeXmlNode be extended to detect numbers?

I am converting from XML to JSON using SerializeXmlNode. Looks the expected behavior is to convert all XML values to strings, but I'd like to emit true numeric values where appropriate.

// Input:   <Type>1</Type>
string json = JsonConvert.SerializeXmlNode(node, Newtonsoft.Json.Formatting.Indented, true);
// Output:  "Type": "1"
// Desired: "Type": 1

Do I need to write a custom converter to do this, or is there a way to hook into the serialization process at the appropriate points, through delegates perhaps? Or, must I write my own custom JsonConverter class to manage the transition?

Regex Hack

Given the complexity of a proper solution, here is another (which I'm not entirely proud of, but it works...).

// Convert to JSON, and remove quotes around numbers
string json = JsonConvert.SerializeXmlNode(node, Newtonsoft.Json.Formatting.Indented, true);

// HACK to force integers as numbers, not strings.
Regex rgx = new Regex("\"(\\d+)\"");
json = rgx.Replace(json, "$1");

Upvotes: 3

Views: 2473

Answers (1)

Brian Rogers
Brian Rogers

Reputation: 129777

XML does not have a way to differentiate primitive types like JSON does. Therefore, when converting XML directly to JSON, Json.Net does not know what types the values should be, short of guessing. If it always assumed that values consisting only of digits were ordinal numbers, then things like postal codes and phone numbers with leading zeros would get mangled in the conversion. It is not surprising, then, that Json.Net takes the safe road and treats all values as string.

One way to work around this issue is to deserialize your XML to an intermediate object, then serialize that to JSON. Since the intermediate object has strongly typed properties, Json.Net knows what to output. Here is an example:

class Program
{
    static void Main(string[] args)
    {
        string xml = @"<root><ordinal>1</ordinal><postal>02345</postal></root>";

        XmlSerializer xs = new XmlSerializer(typeof(Intermediary));
        using (TextReader reader = new StringReader(xml))
        {
            Intermediary obj = (Intermediary)xs.Deserialize(reader);
            string json = JsonConvert.SerializeObject(obj , Formatting.Indented);
            Console.WriteLine(json);
        }
    }
}

[XmlRoot("root")]
public class Intermediary
{
    public int ordinal { get; set; }
    public string postal { get; set; }
}

Output of the above:

{
  "ordinal": 1,
  "postal": "02345"
}

To make a more generic solution, yes, you'd have to write your own converter. In fact, the XML-to-JSON conversion that takes place when calling SerializeXmlNode is done using an XmlNodeConverter that ships with Json.Net. This converter itself does not appear to be very extensible, but you could always use its source code as a starting point to creating your own.

Upvotes: 3

Related Questions