I need to write many sample codes for various API's, which demonstrate how to write the code to use those particular REST API's in C# language.
Now for the API's which are HTTP POST calls, a request body is first created as a class object which is then later serialized into a JSON string and passed to the REST Client.
My Requirement is in this part: "Creating the request Body as a class object".
Following example will make the requirement crystal clear:-
Suppose i have the below JSON Data:
{
"workingDays": ["Monday","Wednesday","Friday"],
"employeeInformation": {
"employeeID": "12345",
"name": {
"firstName": "foo",
"lastName": "bar"
}
},
"joiningDate":"23061984"
}
I need to parse the above data and generate the below code (which currently i am writing manually):
// Create Main Request Body Object
var requestBodyObj = new RequestBody();
// Array Case
var workingDaysObj = new List<string>();
workingDaysObj.Add("Monday");
workingDaysObj.Add("Wednesday");
workingDaysObj.Add("Friday");
requestBodyObj.workingDays = workingDaysObj;
// Nested Object Case
var employeeInformationObj = new employeeInformation();
employeeInformationObj.employeeID = "12345";
var nameObj = new name();
nameObj.firstName = "foo";
nameObj.lastName = "bar";
employeeInformationObj.name = nameObj;
requestBodyObj.employeeInformation = employeeInformationObj;
// Simple Name/Value Pair
requestBodyObj.joiningDate = "23061984";
So as per the above example the JSON Data can be in one of the following 2 forms as well (apart from simple name/value pairs):
Array
Nested Object
And both these cases should be handled as shown in the above code.
Note: User will not be provided with a JSON file so i can't write any code which directly reads a JSON file, deserializes it and assigns the values to a class object using (for example) a NewtonSoft function:
// read file into a string and deserialize JSON to a type
Movie movie1 = JsonConvert.DeserializeObject<Movie>(File.ReadAllText(#"c:\movie.json"));
// deserialize JSON directly from a file
using (StreamReader file = File.OpenText(#"c:\movie.json"))
{
JsonSerializer serializer = new JsonSerializer();
Movie movie2 = (Movie)serializer.Deserialize(file, typeof(Movie));
}
I just want a simple "JSON parser and C# Code generator" (Preferably written in C# language itself).
Any suggestions or pointers will be appreciated.
Edit Update
Pascal Case setting for variable names
Json Object names can be mapped to Project model classes
Write the output to text file for easy copy
Updated Code Below:-
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Newtonsoft.Json;
namespace SampleCodeCreator
{
class Program
{
// Declaring the variables
static string jsonFilePath = #"[Your File Path]";
static string outputFilePath = #"[Your File Path]";
static string jsonData;
static Dictionary<string, string> classMap = new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase);
static void Main(string[] args)
{
// Initializing Class map which is used to map the json object to Project Model Class
InitializeClassMap();
// clear current data in the output file
using (System.IO.StreamWriter file = new System.IO.StreamWriter(outputFilePath, false))
{
file.Write(String.Empty);
}
// read the json data file and store the data in a simple string
using (StreamReader r = new StreamReader(jsonFilePath))
{
jsonData = r.ReadToEnd();
}
// Call the method for the whole json data
PrintJsonObject("RequestBody", jsonData);
}
static void PrintJsonObject(string parentObject, string jsonData)
{
// if the parent object has any mapped class, then set the object name
parentObject = MappedClass(parentObject);
Console.WriteLine("var {0}Obj = new {1}();", ToCamelCase(parentObject), parentObject);
SetOutput("var " + ToCamelCase(parentObject) + "Obj = new " + parentObject + "();");
Console.WriteLine("");
SetOutput("");
// Deserialize the Json data and iterate through each of its sub-sections
var jsonSubData = JsonConvert.DeserializeObject<Dictionary<string, object>>(jsonData);
foreach (var data in jsonSubData)
{
var dataKey = data.Key;
var dataValue = data.Value;
// array case (if the sub element is an array)
if (dataValue.ToString().Contains("["))
{
PrintArrayCase(dataKey, dataValue);
Console.WriteLine("{0}Obj.{1} = {1}Obj;", ToCamelCase(parentObject), dataKey);
SetOutput(ToCamelCase(parentObject) + "Obj." + dataKey + " = " + dataKey + "Obj;");
Console.WriteLine("");
SetOutput("");
}
// nested object case (if the sub element itself contains another json format body)
else if (dataValue.ToString().Contains("{"))
{
// Recursive Call
PrintJsonObject(dataKey, dataValue.ToString());
Console.WriteLine("{0}Obj.{1} = {1}Obj;", ToCamelCase(parentObject), dataKey);
SetOutput(ToCamelCase(parentObject) + "Obj." + dataKey + " = " + dataKey + "Obj;");
Console.WriteLine("");
SetOutput("");
}
// simple key value pair case
else
{
PrintKeyValuePairCase(parentObject, dataKey, dataValue.ToString());
}
}
}
static void PrintArrayCase(string key, object obj)
{
Console.WriteLine("var {0}Obj = new List<string>();", key);
SetOutput("var " + key + "Obj = new List<string>();");
// The array value is split into its values
// e.g. [abc, def, ghi] -> [abc] [def] [ghi]
var valueString = obj.ToString();
var valueSplitArray = valueString.Split(',');
for (int k = 0; k < valueSplitArray.Count(); k++)
{
string listValue = "";
if (k != valueSplitArray.Count() - 1)
{
var startIndex = valueSplitArray[k].IndexOf("\"");
listValue = valueSplitArray[k].Substring(startIndex + 1, valueSplitArray[k].Length - startIndex - 2);
}
else
{
var startIndex = valueSplitArray[k].IndexOf("\"");
listValue = valueSplitArray[k].Substring(startIndex + 1, valueSplitArray[k].Length - startIndex - 5);
}
// each value is then added to the main list object
Console.WriteLine(#"{0}Obj.Add(""{1}"");", ToCamelCase(key), listValue);
SetOutput(#""+ToCamelCase(key)+#"Obj.Add("""+listValue+#""");");
}
Console.WriteLine("");
SetOutput("");
}
static void PrintKeyValuePairCase(string parentObj, string key, string value)
{
Console.WriteLine("{0}Obj.{1} = \"{2}\";", ToCamelCase(parentObj), key, value);
SetOutput("" + ToCamelCase(parentObj) + "Obj." + key + " = \"" + value + "\";");
}
static string ToCamelCase(string str)
{
if (!String.IsNullOrEmpty(str))
{
return str.Substring(0, 1).ToLower() + str.Substring(1, str.Length - 1);
}
else
{
return null;
}
}
static string MappedClass(string str)
{
if (classMap.ContainsKey(str))
return classMap[str];
else
return str;
}
static void InitializeClassMap()
{
classMap.Add("employeeInformation", "EmployeeInfo");
}
static void SetOutput(string str)
{
using (System.IO.StreamWriter file = new System.IO.StreamWriter(outputFilePath, true))
{
file.WriteLine(str);
}
}
}
}
I retrieved a list of users from database, something like
List<User> users = <..list of users from db...>
Name, LastName, DateOfBirth //multidimensional array??
Now I want to store this list as a string and I want be able to reuse it i.e.
string strUsers = users.ToArray().ToString();
How to recreate a list of users from strUsers?
Is it possible?
Use the string.Join method, e.g.
var joined = string.Join(",", users.Select(u => u.Name));
This would give you a single string of user's names separated by ','.
Or for multiple columns:
var joined = string.Join(",",
users.Select(u => u.FirstName + " " + u.LastName ));
You can reverse the process using string.Split, e.g.
var split = joined.Split( new [] {','} );
If you have a lot of users and a lot of columns, it would be better to write your own custom converter class.
public static class UsersConverter
{
// Separates user properties.
private const char UserDataSeparator = ',';
// Separates users in the list.
private const char UsersSeparator = ';';
public static string ConvertListToString(IEnumerable<User> usersList)
{
var stringBuilder = new StringBuilder();
// Build the users string.
foreach (User user in usersList)
{
stringBuilder.Append(user.Name);
stringBuilder.Append(UserDataSeparator);
stringBuilder.Append(user.Age);
stringBuilder.Append(UsersSeparator);
}
// Remove trailing separator.
stringBuilder.Remove(stringBuilder.Length - 1, 1);
return stringBuilder.ToString();
}
public static List<User> ParseStringToList(string usersString)
{
// Check that passed argument is not null.
if (usersString == null) throw new ArgumentNullException("usersString");
var result = new List<User>();
string[] userDatas = usersString.Split(UsersSeparator);
foreach (string[] userData in userDatas.Select(x => x.Split(UserDataSeparator)))
{
// Check that user data contains enough arguments.
if (userData.Length < 2) throw new ArgumentException("Users string contains invalid data.");
string name = userData[0];
int age;
// Try parsing age.
if (!int.TryParse(userData[1], out age))
{
throw new ArgumentException("Users string contains invalid data.");
}
// Add to result list.
result.Add(new User { Name = name, Age = age });
}
return result;
}
}
You will win performance wise using the StringBuilder to build up your users string. You could also easily expand the converter to take account different separators/additional logic etc.
If you need a more generic solution (to be able to use for any class), you could create a converter which uses reflection to iterate over all the public fields, get/set properties to see what can be extracted as string and later reverse the process to convert your string back to the list.
I think what you're looking for is something that lets you dump all users to a string and get the users back from the string, correct?
I suggest something like this:
Add a method that returns an XElement to the Users type:
public XElement GetXElement()
{
return new XElement("User", new XElement("Name", this.FirstName)) //and so on...
}
and then one that decodes the string into a user:
static User GetUserFromXElement(string xml)
{
XElement temp = XElement.Parse(xml);
User temp = new User();
foreach (XElement inner in temp.Elements())
{
switch inner.Name
{
case "Name":
temp.Name = inner.Value
break;
//whatever
}
}
}
And then do this:
public string UsersToElements (List<Users> toWrite)
{
Stringbuilder sb = new StringBuilder();
StringWriter sw = new StringWriter(sb);
XElement root = new XElement("root");
XDocument temp = new XDocument(root);
foreach (User user in toWrite)
{
root.Append(user.GetXElement());
}
temp.Save(sw);
return sw.ToString();
}
and this:
public List<Users> ElementsToUsers (string xml)
{
List<Users> usrsList = new List<Users>();
XDocument temp = XDocument.Load(xml);
foreach (XElement e in XDocument.Root.Elements())
{
usrsList.Append(Users.GetUserFromXElement(e));
}
return usrsList;
}
JSON solution (using JSON.NET)
public JObject GetJObject()
{
return new JObject("user", new JProperty("name", this.FirstName)); //so on
}
static User GetUserFromJObject(string json)
{
JObject obj = JObject.Parse(json);
return new User() { FirstName = (string)obj["user"]["name"] }; //so on
}
public string UsersToElements (List<Users> users)
{
JObject root = new JObject(from usr in users select new JAttribute("user", usr.GetJObject());
return root.ToString();
}
public List<users> ElementsToUsers(string json)
{
List<Users> users = new List<Users>();
JObject temp = JObject.Parse(json);
foreach (JObject o in (JEnumerable<JObject>)temp.Children())
{
users.Add(Users.GetUserFromJObject(o.ToString());
}
return users;
}
I have no idea if ths works :/ (well the XML I know it does, not so sure about the JSON)
Use this code
string combindedString = string.Join( ",", myList );
var Array = combindedString.Split( new [] {','} );
I have the following xml
<Objects>
<Object>
<ViewAngle>90</ViewAngle>
<ViewMode>ThirdPerson</ViewMode>
<Top>50</Top>
<Left>100</Left>
</Object>
</Objects>
I have the following code to read this xml
XmlDataDocument doc = new XmlDataDocument();
doc.Load(xmlPath);
XmlElement root = doc.DocumentElement;
XmlNodeList nodes = root.SelectNodes("/Objects/Object");
foreach (XmlNode node in nodes)
{
if (node.InnerXml.Contains("View"))
{
string viewType=node["View"].InnerText;
//..... other stuffs
}
if (node.InnerXml.Contains("ViewAngle"))
{
string viewAngle=node["ViewAngle"].InnerText;
//..... other stuffs
}
if (node.InnerXml.Contains("ViewMode"))
{
string viewMode=node["ViewMode"].InnerText;
//..... other stuffs
}
}
Above code is working fine if my xml contains one more tag i.e. <View>3dView</View>. But if it does not contains the View tag, then it produces error.
The InnerXml.Contains() is a simple string method that checks for the sub-string is present in the string or not.
In my case the Contains("View") returns true as View is present in ViewAngle and in ViewMode that is why it is going inside the if block of View but when it tries to read the node["View"], it produces error as View node is not exists in the xml.
How to resolve this error?
You are missing the fact that XML is structured data, not string. This is completely the wrong approach:
if (node.InnerXml.Contains("View")) {
// ...
}
You want this:
XmlNode child = node.SelectSingleNode("./View");
if (child != null) {
// now do something with 'child' ...
}
Try this loop instead:
foreach (XmlNode node in nodes) {
foreach (XmlNode prop in node.ChildNodes) {
if (prop.NodeType != XmlNodeType.Element)
continue;
switch (prop.Name) {
case "View":
string viewType = prop.InnerText;
// ...
break;
case "ViewAngle":
string viewAngle = prop.InnerText;
// ...
break;
case "ViewMode":
string viewMode = prop.InnerText;
// ...
break;
}
}
}
If the View element is not present, it cannot be found. You can use the GetElementsByTagName("View") method instead. This will return null if the view element is not there.
You can make some modifications in this function and use it acordingly
XDocument xDoc=XDocument.Load(#"C:\File.xml");
Process(xDoc.Root);
public static void Process(XElement element)
{
if (element.HasElements)
{
Console.WriteLine("<" + element.Name.LocalName + ">");
foreach (XElement child in element.Elements())
{
Process(child);
}
Console.WriteLine("<" + element.Name.LocalName + ">");
}
else
{
Console.WriteLine("<" + element.Name.LocalName);
if(element.HasAttributes)
{
foreach (XAttribute attr in element.Attributes())
{
Console.WriteLine(attr.Name +"="+attr.Value);
}
}
Console.WriteLine(">" + element.Value + "</" + element.Name.LocalName + ">");
}
}
if trageting 3.5 or above u can use linq
XDocument XDoc = XDocument.Load(#"C:\UrXMLFile.xml");
var q = from b in xml.Descendants("product")
select new
{
View = (string)b.Element("View") ?? "3dView",
ViewAngle = (double?)b.Element("ViewAngle") ?? 90.0,
ViewMode = (string)b.Element("ViewMode") ?? ThirdPerson,
Top = (double?)b.Element("Top") ?? 0.0,
Left = (double?)b.Element("Left") ?? 0.0
};
So if View is not found it have a default value always. Also u can create ur class object in select new. Note: I have not compiled it.
I started to use Json.NET to convert a string in JSON format to object or viceversa. I am not sure in the Json.NET framework, is it possible to convert a string in JSON to XML format and viceversa?
Yes. Using the JsonConvert class which contains helper methods for this precise purpose:
// To convert an XML node contained in string xml into a JSON string
XmlDocument doc = new XmlDocument();
doc.LoadXml(xml);
string jsonText = JsonConvert.SerializeXmlNode(doc);
// To convert JSON text contained in string json into an XML node
XmlDocument doc = JsonConvert.DeserializeXmlNode(json);
Documentation here: Converting between JSON and XML with Json.NET
Yes, you can do it (I do) but Be aware of some paradoxes when converting, and handle appropriately. You cannot automatically conform to all interface possibilities, and there is limited built-in support in controlling the conversion- many JSON structures and values cannot automatically be converted both ways. Keep in mind I am using the default settings with Newtonsoft JSON library and MS XML library, so your mileage may vary:
XML -> JSON
All data becomes string data (for example you will always get "false" not false or "0" not 0) Obviously JavaScript treats these differently in certain cases.
Children elements can become nested-object {} OR nested-array [ {} {} ...] depending if there is only one or more than one XML child-element. You would consume these two differently in JavaScript, etc. Different examples of XML conforming to the same schema can produce actually different JSON structures this way. You can add the attribute json:Array='true' to your element to workaround this in some (but not necessarily all) cases.
Your XML must be fairly well-formed, I have noticed it doesn't need to perfectly conform to W3C standard, but 1. you must have a root element and 2. you cannot start element names with numbers are two of the enforced XML standards I have found when using Newtonsoft and MS libraries.
In older versions, Blank elements do not convert to JSON. They are ignored. A blank element does not become "element":null
A new update changes how null can be handled (Thanks to Jon Story for pointing it out): https://www.newtonsoft.com/json/help/html/T_Newtonsoft_Json_NullValueHandling.htm
JSON -> XML
You need a top level object that will convert to a root XML element or the parser will fail.
Your object names cannot start with a number, as they cannot be converted to elements (XML is technically even more strict than this) but I can 'get away' with breaking some of the other element naming rules.
Please feel free to mention any other issues you have noticed, I have developed my own custom routines for preparing and cleaning the strings as I convert back and forth. Your situation may or may not call for prep/cleanup. As StaxMan mentions, your situation may actually require that you convert between objects...this could entail appropriate interfaces and a bunch of case statements/etc to handle the caveats I mention above.
You can do these conversions also with the .NET Framework:
JSON to XML: by using System.Runtime.Serialization.Json
var xml = XDocument.Load(JsonReaderWriterFactory.CreateJsonReader(
Encoding.ASCII.GetBytes(jsonString), new XmlDictionaryReaderQuotas()));
XML to JSON: by using System.Web.Script.Serialization
var json = new JavaScriptSerializer().Serialize(GetXmlData(XElement.Parse(xmlString)));
private static Dictionary<string, object> GetXmlData(XElement xml)
{
var attr = xml.Attributes().ToDictionary(d => d.Name.LocalName, d => (object)d.Value);
if (xml.HasElements) attr.Add("_value", xml.Elements().Select(e => GetXmlData(e)));
else if (!xml.IsEmpty) attr.Add("_value", xml.Value);
return new Dictionary<string, object> { { xml.Name.LocalName, attr } };
}
I'm not sure there is point in such conversion (yes, many do it, but mostly to force a square peg through round hole) -- there is structural impedance mismatch, and conversion is lossy. So I would recommend against such format-to-format transformations.
But if you do it, first convert from json to object, then from object to xml (and vice versa for reverse direction). Doing direct transformation leads to ugly output, loss of information, or possibly both.
Thanks for David Brown's answer. In my case of JSON.Net 3.5, the convert methods are under the JsonConvert static class:
XmlNode myXmlNode = JsonConvert.DeserializeXmlNode(myJsonString); // is node not note
// or .DeserilizeXmlNode(myJsonString, "root"); // if myJsonString does not have a root
string jsonString = JsonConvert.SerializeXmlNode(myXmlNode);
I searched for a long time to find alternative code to the accepted solution in the hopes of not using an external assembly/project. I came up with the following thanks to the source code of the DynamicJson project:
public XmlDocument JsonToXML(string json)
{
XmlDocument doc = new XmlDocument();
using (var reader = JsonReaderWriterFactory.CreateJsonReader(Encoding.UTF8.GetBytes(json), XmlDictionaryReaderQuotas.Max))
{
XElement xml = XElement.Load(reader);
doc.LoadXml(xml.ToString());
}
return doc;
}
Note: I wanted an XmlDocument rather than an XElement for xPath purposes.
Also, this code obviously only goes from JSON to XML, there are various ways to do the opposite.
Here is the full c# code to convert xml to json
public static class JSon
{
public static string XmlToJSON(string xml)
{
XmlDocument doc = new XmlDocument();
doc.LoadXml(xml);
return XmlToJSON(doc);
}
public static string XmlToJSON(XmlDocument xmlDoc)
{
StringBuilder sbJSON = new StringBuilder();
sbJSON.Append("{ ");
XmlToJSONnode(sbJSON, xmlDoc.DocumentElement, true);
sbJSON.Append("}");
return sbJSON.ToString();
}
// XmlToJSONnode: Output an XmlElement, possibly as part of a higher array
private static void XmlToJSONnode(StringBuilder sbJSON, XmlElement node, bool showNodeName)
{
if (showNodeName)
sbJSON.Append("\"" + SafeJSON(node.Name) + "\": ");
sbJSON.Append("{");
// Build a sorted list of key-value pairs
// where key is case-sensitive nodeName
// value is an ArrayList of string or XmlElement
// so that we know whether the nodeName is an array or not.
SortedList<string, object> childNodeNames = new SortedList<string, object>();
// Add in all node attributes
if (node.Attributes != null)
foreach (XmlAttribute attr in node.Attributes)
StoreChildNode(childNodeNames, attr.Name, attr.InnerText);
// Add in all nodes
foreach (XmlNode cnode in node.ChildNodes)
{
if (cnode is XmlText)
StoreChildNode(childNodeNames, "value", cnode.InnerText);
else if (cnode is XmlElement)
StoreChildNode(childNodeNames, cnode.Name, cnode);
}
// Now output all stored info
foreach (string childname in childNodeNames.Keys)
{
List<object> alChild = (List<object>)childNodeNames[childname];
if (alChild.Count == 1)
OutputNode(childname, alChild[0], sbJSON, true);
else
{
sbJSON.Append(" \"" + SafeJSON(childname) + "\": [ ");
foreach (object Child in alChild)
OutputNode(childname, Child, sbJSON, false);
sbJSON.Remove(sbJSON.Length - 2, 2);
sbJSON.Append(" ], ");
}
}
sbJSON.Remove(sbJSON.Length - 2, 2);
sbJSON.Append(" }");
}
// StoreChildNode: Store data associated with each nodeName
// so that we know whether the nodeName is an array or not.
private static void StoreChildNode(SortedList<string, object> childNodeNames, string nodeName, object nodeValue)
{
// Pre-process contraction of XmlElement-s
if (nodeValue is XmlElement)
{
// Convert <aa></aa> into "aa":null
// <aa>xx</aa> into "aa":"xx"
XmlNode cnode = (XmlNode)nodeValue;
if (cnode.Attributes.Count == 0)
{
XmlNodeList children = cnode.ChildNodes;
if (children.Count == 0)
nodeValue = null;
else if (children.Count == 1 && (children[0] is XmlText))
nodeValue = ((XmlText)(children[0])).InnerText;
}
}
// Add nodeValue to ArrayList associated with each nodeName
// If nodeName doesn't exist then add it
List<object> ValuesAL;
if (childNodeNames.ContainsKey(nodeName))
{
ValuesAL = (List<object>)childNodeNames[nodeName];
}
else
{
ValuesAL = new List<object>();
childNodeNames[nodeName] = ValuesAL;
}
ValuesAL.Add(nodeValue);
}
private static void OutputNode(string childname, object alChild, StringBuilder sbJSON, bool showNodeName)
{
if (alChild == null)
{
if (showNodeName)
sbJSON.Append("\"" + SafeJSON(childname) + "\": ");
sbJSON.Append("null");
}
else if (alChild is string)
{
if (showNodeName)
sbJSON.Append("\"" + SafeJSON(childname) + "\": ");
string sChild = (string)alChild;
sChild = sChild.Trim();
sbJSON.Append("\"" + SafeJSON(sChild) + "\"");
}
else
XmlToJSONnode(sbJSON, (XmlElement)alChild, showNodeName);
sbJSON.Append(", ");
}
// Make a string safe for JSON
private static string SafeJSON(string sIn)
{
StringBuilder sbOut = new StringBuilder(sIn.Length);
foreach (char ch in sIn)
{
if (Char.IsControl(ch) || ch == '\'')
{
int ich = (int)ch;
sbOut.Append(#"\u" + ich.ToString("x4"));
continue;
}
else if (ch == '\"' || ch == '\\' || ch == '/')
{
sbOut.Append('\\');
}
sbOut.Append(ch);
}
return sbOut.ToString();
}
}
To convert a given XML string to JSON, simply call XmlToJSON() function as below.
string xml = "<menu id=\"file\" value=\"File\"> " +
"<popup>" +
"<menuitem value=\"New\" onclick=\"CreateNewDoc()\" />" +
"<menuitem value=\"Open\" onclick=\"OpenDoc()\" />" +
"<menuitem value=\"Close\" onclick=\"CloseDoc()\" />" +
"</popup>" +
"</menu>";
string json = JSON.XmlToJSON(xml);
// json = { "menu": {"id": "file", "popup": { "menuitem": [ {"onclick": "CreateNewDoc()", "value": "New" }, {"onclick": "OpenDoc()", "value": "Open" }, {"onclick": "CloseDoc()", "value": "Close" } ] }, "value": "File" }}
For convert JSON string to XML try this:
public string JsonToXML(string json)
{
XDocument xmlDoc = new XDocument(new XDeclaration("1.0", "utf-8", ""));
XElement root = new XElement("Root");
root.Name = "Result";
var dataTable = JsonConvert.DeserializeObject<DataTable>(json);
root.Add(
from row in dataTable.AsEnumerable()
select new XElement("Record",
from column in dataTable.Columns.Cast<DataColumn>()
select new XElement(column.ColumnName, row[column])
)
);
xmlDoc.Add(root);
return xmlDoc.ToString();
}
For convert XML to JSON try this:
public string XmlToJson(string xml)
{
XmlDocument doc = new XmlDocument();
doc.LoadXml(xml);
string jsonText = JsonConvert.SerializeXmlNode(doc);
return jsonText;
}
Here is a simple snippet that converts a XmlNode (recursively) into a hashtable, and groups multiple instances of the same child into an array (as an ArrayList).
The Hashtable is usually accepted to convert into JSON by most of the JSON libraries.
protected object convert(XmlNode root){
Hashtable obj = new Hashtable();
for(int i=0,n=root.ChildNodes.Count;i<n;i++){
object result = null;
XmlNode current = root.ChildNodes.Item(i);
if(current.NodeType != XmlNodeType.Text)
result = convert(current);
else{
int resultInt;
double resultFloat;
bool resultBoolean;
if(Int32.TryParse(current.Value, out resultInt)) return resultInt;
if(Double.TryParse(current.Value, out resultFloat)) return resultFloat;
if(Boolean.TryParse(current.Value, out resultBoolean)) return resultBoolean;
return current.Value;
}
if(obj[current.Name] == null)
obj[current.Name] = result;
else if(obj[current.Name].GetType().Equals(typeof(ArrayList)))
((ArrayList)obj[current.Name]).Add(result);
else{
ArrayList collision = new ArrayList();
collision.Add(obj[current.Name]);
collision.Add(result);
obj[current.Name] = collision;
}
}
return obj;
}
Try this function. I just wrote it and haven't had much of a chance to test it, but my preliminary tests are promising.
public static XmlDocument JsonToXml(string json)
{
XmlNode newNode = null;
XmlNode appendToNode = null;
XmlDocument returnXmlDoc = new XmlDocument();
returnXmlDoc.LoadXml("<Document />");
XmlNode rootNode = returnXmlDoc.SelectSingleNode("Document");
appendToNode = rootNode;
string[] arrElementData;
string[] arrElements = json.Split('\r');
foreach (string element in arrElements)
{
string processElement = element.Replace("\r", "").Replace("\n", "").Replace("\t", "").Trim();
if ((processElement.IndexOf("}") > -1 || processElement.IndexOf("]") > -1) && appendToNode != rootNode)
{
appendToNode = appendToNode.ParentNode;
}
else if (processElement.IndexOf("[") > -1)
{
processElement = processElement.Replace(":", "").Replace("[", "").Replace("\"", "").Trim();
newNode = returnXmlDoc.CreateElement(processElement);
appendToNode.AppendChild(newNode);
appendToNode = newNode;
}
else if (processElement.IndexOf("{") > -1 && processElement.IndexOf(":") > -1)
{
processElement = processElement.Replace(":", "").Replace("{", "").Replace("\"", "").Trim();
newNode = returnXmlDoc.CreateElement(processElement);
appendToNode.AppendChild(newNode);
appendToNode = newNode;
}
else
{
if (processElement.IndexOf(":") > -1)
{
arrElementData = processElement.Replace(": \"", ":").Replace("\",", "").Replace("\"", "").Split(':');
newNode = returnXmlDoc.CreateElement(arrElementData[0]);
for (int i = 1; i < arrElementData.Length; i++)
{
newNode.InnerText += arrElementData[i];
}
appendToNode.AppendChild(newNode);
}
}
}
return returnXmlDoc;
}
I did like David Brown said but I got the following exception.
$exception {"There are multiple root elements. Line , position ."} System.Xml.XmlException
One solution would be to modify the XML file with a root element but that is not always necessary and for an XML stream it might not be possible either. My solution below:
var path = Path.GetFullPath(Path.Combine(Environment.CurrentDirectory, #"..\..\App_Data"));
var directoryInfo = new DirectoryInfo(path);
var fileInfos = directoryInfo.GetFiles("*.xml");
foreach (var fileInfo in fileInfos)
{
XmlDocument doc = new XmlDocument();
XmlReaderSettings settings = new XmlReaderSettings();
settings.ConformanceLevel = ConformanceLevel.Fragment;
using (XmlReader reader = XmlReader.Create(fileInfo.FullName, settings))
{
while (reader.Read())
{
if (reader.NodeType == XmlNodeType.Element)
{
var node = doc.ReadNode(reader);
string json = JsonConvert.SerializeXmlNode(node);
}
}
}
}
Example XML that generates the error:
<parent>
<child>
Text
</child>
</parent>
<parent>
<child>
<grandchild>
Text
</grandchild>
<grandchild>
Text
</grandchild>
</child>
<child>
Text
</child>
</parent>
I have used the below methods to convert the JSON to XML
List <Item> items;
public void LoadJsonAndReadToXML() {
using(StreamReader r = new StreamReader(# "E:\Json\overiddenhotelranks.json")) {
string json = r.ReadToEnd();
items = JsonConvert.DeserializeObject <List<Item>> (json);
ReadToXML();
}
}
And
public void ReadToXML() {
try {
var xEle = new XElement("Items",
from item in items select new XElement("Item",
new XElement("mhid", item.mhid),
new XElement("hotelName", item.hotelName),
new XElement("destination", item.destination),
new XElement("destinationID", item.destinationID),
new XElement("rank", item.rank),
new XElement("toDisplayOnFod", item.toDisplayOnFod),
new XElement("comment", item.comment),
new XElement("Destinationcode", item.Destinationcode),
new XElement("LoadDate", item.LoadDate)
));
xEle.Save("E:\\employees.xml");
Console.WriteLine("Converted to XML");
} catch (Exception ex) {
Console.WriteLine(ex.Message);
}
Console.ReadLine();
}
I have used the class named Item to represent the elements
public class Item {
public int mhid { get; set; }
public string hotelName { get; set; }
public string destination { get; set; }
public int destinationID { get; set; }
public int rank { get; set; }
public int toDisplayOnFod { get; set; }
public string comment { get; set; }
public string Destinationcode { get; set; }
public string LoadDate { get; set; }
}
It works....
Cinchoo ETL - an open source library available to do the conversion of Xml to JSON easily with few lines of code
Xml -> JSON:
using (var p = new ChoXmlReader("sample.xml"))
{
using (var w = new ChoJSONWriter("sample.json"))
{
w.Write(p);
}
}
JSON -> Xml:
using (var p = new ChoJsonReader("sample.json"))
{
using (var w = new ChoXmlWriter("sample.xml"))
{
w.Write(p);
}
}
Sample fiddle: https://dotnetfiddle.net/enUJKu
Checkout CodeProject articles for some additional help.
Disclaimer: I'm the author of this library.
Here's an example of how to convert JSON to XML using .NET built-in libraries (instead of 3rd party libraries like Newtonsoft).
using System.Text.Json;
using System.Text.Json.Nodes;
using System.Xml.Linq;
XDocument xmlDoc = jsonToXml(jsonObj);
private XDocument jsonToXml(JsonObject obj)
{
var xmlDoc = new XDocument();
var root = new XElement("Root");
xmlDoc.Add(root);
foreach (var prop in obj)
{
var xElement = new XElement(prop.Key);
xElement.Value = prop.Value.ToString();
root.Add(xElement);
}
return xmlDoc;
}