Json To Xml : Wrapping the Array Elements

In this post, we will look into a scenario when you need to convert a Json to XML, but at the same time need to add a wrapping Property for each array. For example, consider the following Json

{
    reportId : 23232,
    submittedBy : 'Anu Viswan',
    projects:[
        {
            id:1001,
            name:'Project 1',
        },
        {
            id:1002,
            name:'Project 2',
        },
        {
            id:1003,
            name:'Project 3',
        },
    ]
}

Deserializing the following to Xml using Json.Net would normally produce the following

var xmlResult = (XmlDocument)JsonConvert.DeserializeXmlNode(jsonString,"root");

Current Result

<root>
   <reportId>23232</reportId>
   <submittedBy>Anu Viswan</submittedBy>
   <projects>
      <id>1001</id>
      <name>Project 1</name>
   </projects>
   <projects>
      <id>1002</id>
      <name>Project 2</name>
   </projects>
   <projects>
      <id>1003</id>
      <name>Project 3</name>
   </projects>
</root>

However, we would like a bit of tweak here. The expected result is as follows.

<tag>
   <reportId>23232</reportId>
   <submittedBy>Anu Viswan</submittedBy>
   <projects>
      <project>
         <id>1001</id>
         <name>Project 1</name>
      </project>
      <project>
         <id>1002</id>
         <name>Project 2</name>
      </project>
      <project>
         <id>1003</id>
         <name>Project 3</name>
      </project>
   </projects>
</tag>

As you can observe, what we require is to insert wrapping element around each of the items in the collection projects. This could of course be done by manipulating the Xml as part of post processing, but, it turns out there is another way to do it in one step.

You could write a custom XmlNodeConverter that would insert a parent element if the current element is an array. For example,

public class ArrayXmlNodeConverter : XmlNodeConverter
{
    public readonly string _arrayRootName;

	public ArrayXmlNodeConverter(string rootElement,string arrayRootName)
	{
		(DeserializeRootElementName,_arrayRootName) = (rootElement,arrayRootName);
	}
    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        var token = JObject.Load(reader);
        ChangeArrayElementRoot(token);
        reader = token.CreateReader();
        reader.Read();
        return base.ReadJson(reader, objectType, existingValue, serializer);
    }

    private void ChangeArrayElementRoot(JToken token)
    {
	    if (token.Type == JTokenType.Array)
        {
            var arrayHolder = new JObject { { _arrayRootName, token } };
            token.Replace(arrayHolder);
        }
		else
		{
		    foreach (var childToken in token)
	        {
	            ChangeArrayElementRoot(childToken);
	        }
		}
    }
}

Now you could use the custom XmlConverter for your deserialization to get the expected result.

var xmlResult = (XmlDocument)JsonConvert.DeserializeObject(jsonString,
                   typeof(XmlDocument), 
                   new ArrayXmlNodeConverter("tag","project"));

This ensured we are deserializing and adding the extra wrapping property in a single step, rather than post processing the converted Xml.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s