Transforming data from JSON to XML and XML to JSON with C#
Tags: xml, json, azure, csharp
Published: 2020-09-22 13:14:13

## Table of Contents

1 [Objective](#objective)  
2 [Data Transfer Object (DTO) and data samples](#dto)  
3 [Root node / root property](#root)  
    3.1 [Add root property to JSON](#addroot)  
    3.2 [Remove root property from JSON](#removeroot)  
4 [Transformation](#transformation)  
    4.1 [Transform JSON into XML](#transformjsonintoxml)  
    4.2 [Transform XML into JSON](#transformxmlintojson)  
5 [Azure Function](#azurefunction)  
6 [Alternative - Newtonsoft](#alternativenewtonsoft)  
7 [Complete solution](#completesolution)


## 1 Objective <a id="objective "></a>

A JSON document has to be transformed into XML. If the XML is transformed back into JSON, the initial JSON has to equal the transformed back JSON.
The solution will be provided as an Azure Function.

![Sequence Diagram](https://dev-to-uploads.s3.amazonaws.com/i/tbx8m322img602xh5a1q.png)

Additional requirements which have to be met:

- JSON-Document has to contain a root property
- Data types have to be specified (string, int, boolean,...)
- XML Attributes has to be supported


## 2 Data Transfer Object (DTO) and data samples <a id="dto"></a>

To ensure that XML-attributes and data types can be used, a C# DTO is required.
Like the required XML root node, the JSON document shall also have a root property.

_Person class:_

```c#
[XmlRoot("person")]
[JsonObject(Title = "Person")]
public class Person
{
    [XmlElement("firstname")]
    public string FirstName { get; set; }

    [XmlElement("lastname")]
    public string LastName { get; set; }

    [XmlAttribute("gender")]
    public string Gender { get; set; }

    [XmlElement("age")]
    public int Age { get; set; }
}
```

_XML for Person class:_

```xml
<?xml version="1.0" encoding="utf-8" ?>
<person gender="female">
  <firstname>Anna</firstname>
  <lastname>Smith</lastname>
  <age>42</age>
</person>
```

_JSON for Person class:_

```json
{
  "Person": {
    "FirstName": "Anna",
    "LastName": "Smith",
    "Gender": "female",
    "Age": 42
  }
}
```


## 3 Root node / root property <a id="root"></a>

Unfortunately, it's not straight forward to have a root property in JSON.
Usually, I do not have to care about, because I'm only using JSON documents.
Then I use a _wrapper class_:

```c#
public class PersonRoot
{
    public Person Person { get; set; }
}

public class Person
{
    public string FirstName { get; set; }
    
    // ...
}

```

In my current case, I do not like this way:

The class _PersonRoot_ will only be used for the JSON data.
For the XML data, it's useless.

A solution to solve this problem is using class attribute _[JsonObject(Title = "Person")]_ and add some code.

### 3.1 Add root property to JSON <a id="addroot"></a>

The code below creates a new JObject based on the _JsonObject_ attribute and adds the initial JObject as a child by transforming XML into JSON:

_Add root property:_
```C#

[JsonObject(Title = "Person")]
public class Person
{
    // ... 
}



Person obj = new Person();
var jsonObjectAttribute = typeof(T).GetCustomAttribute(typeof(JsonObjectAttribute)) as JsonObjectAttribute;
var jsonValue = JValue.FromObject(obj);
var jsonObject =  new JObject(new JProperty(jsonObjectAttribute.Title, jsonValue));
```

### 3.2 Remove root property from JSON <a id="removeroot"></a>

The code below creates a new JObject based on the JSON document.
For transforming JSON into XML, the root JSON property has to be removed.
_JsonObject_ attribute is used to get the JSON root property.

_Remove root property:_
```C#
[JsonObject(Title = "Person")]
public class Person
{
    // ... 
}

var jsonObjectAttribute = typeof(T).GetCustomAttribute(typeof(JsonObjectAttribute)) as JsonObjectAttribute;
JObject root = JObject.Parse(json);
var data = root[jsonObjectAttribute.Title];

```

## 4 Transformation <a id="transformation"></a>

It's time to put all the things together. 

### 4.1 Transform JSON into XML <a id="transformjsonintoxml"></a>

The code removes the root property, deserializes the JSON document to the object and the _XmlSerializer_  is used to create an XML string.

_Transform JSON into XML:_
```C#
var result = Transformer.TransformJsonToXml<Person>(json);
```

```C#
public static string TransformJsonToXml<T>(string json)
{
    // Remove root property
    var jsonObjectAttribute = typeof(T).GetCustomAttribute(typeof(JsonObjectAttribute)) as JsonObjectAttribute;
    JObject root = JObject.Parse(json);
    var data = root[jsonObjectAttribute.Title];

    var obj = JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(data));

    var serializer = new XmlSerializer(typeof(T));
    var stringWriter = new StringWriter();
    using var xmlWriter = XmlWriter.Create(stringWriter);
    var xmlSerializerNamespaces = new XmlSerializerNamespaces();
    xmlSerializerNamespaces.Add("","");
    serializer.Serialize(xmlWriter, obj, xmlSerializerNamespaces);
    return stringWriter.ToString();
}


```



### 4.2 Transform XML into JSON <a id="transformxmlintojson"></a>

The code deserializes the XML document by using the _XmlSerializer_ to the object, adds the root property and the serialized object will be returned.

_Transform XML into JSON:_
```C#
var result = Transformer.TransformXmlToJson<Person>(xml);
```

````C#
public static string TransformXmlToJson<T>(string xml)
{
    var serializer = new XmlSerializer(typeof(T));
    using var stringReader = new System.IO.StringReader(xml);
    using var xmlReader = XmlReader.Create(stringReader);
    var obj = (T)serializer.Deserialize(xmlReader);

    // Add root property
    var jsonObjectAttribute = typeof(T).GetCustomAttribute(typeof(JsonObjectAttribute)) as JsonObjectAttribute;
    var jsonValue = JValue.FromObject(obj);
    var jsonObject =  new JObject(new JProperty(jsonObjectAttribute.Title, jsonValue));

    var settings = new JsonSerializerSettings { Formatting = Newtonsoft.Json.Formatting.Indented };
    return JsonConvert.SerializeObject(jsonObject, settings);
}
```
## 5. Azure Function<a id="azurefunction"></a>

This is straight forward for returning the JSON document:
```C#
 return new OkObjectResult(JObject.Parse(result));
```
![image](https://user-images.githubusercontent.com/8818198/93757287-c4348100-fc06-11ea-8bcb-f3af8ba0d19b.png)
For returning the XML document _OkObjectResult_ cannot be used:

```C#
 return new ContentResult() { Content = result, ContentType = "application/xml", StatusCode = 200 };
```
![image](https://user-images.githubusercontent.com/8818198/93757202-9f400e00-fc06-11ea-8477-20593383509d.png)

## 6. Alternative - Newtonsoft<a id="alternativenewtonsoft"></a>

The Newtonsoft JSON library also supports transforming data into JSON or XML:
[Newtonsoft: Converting between JSON and XML](https://www.newtonsoft.com/json/help/html/convertingjsonandxml.htm "Converting between JSON and XML")

But there are a few things which do not match my requirements:
- prefixed attributes
   - so I have to include additional code to get rid of this
- no data types
   - all data types are strings

## 7. Complete solution <a id="completesolution"></a>

The complete solution can be found in my [GitHub repository](https://github.com/MarkusMeyer13/DataTransformation "https://github.com/MarkusMeyer13/DataTransformation").