How would I parse an XML file into a list - c#

List:
List<string> list = new List<string>();
XML File:
<memberlist>
<member>
<name>Name</name>
<status>Status</status>
</member>
</memberlist>
How would I go about parsing this file, lets say (file.xml) into the list?
I've tried many ways but none of them seem to be working.
I want to check to see if the status is 'gold', and if it is, I would like to put the name of that member into the list.

Load the xml into an XDocument. You can do this from a file, I have demonstrated from a string.
Do a linq query for elements named "status" (within "member") that also have a value of "gold".
Of those, grab the value of the "name" element.
Use AddRange on your list of strings.
List<string> lstGolds = new List<string>();
string xml ="<memberlist><member><name>Name</name><status>gold</status></member></memberlist>";
XDocument doc = XDocument.Parse(xml);
var goldStatus = doc.Descendants("member")
.Where(d => d.Element("status").Value == "gold")
.Select(d => d.Element("name").Value);
lstGolds.AddRange(goldStatus);

You should use using System.Xml.Linq;
using (FileStream fileStramWrite = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read))
using (StreamReader streamReader = new StreamReader(fileStramWrite))
{
var xdoc = XDocument.Load(streamReader);
var xElement = xdoc.Element("memberlist");
var xElement2 = xElement.Element("member");
var name = xElement2.Element("name").Value;
var status = xElement2.Element("status").Value;
}

Convert your XML to a list of objects....
Use these two mehods:
public static string Serialize<T>(T dataToSerialize)
{
try
{
var stringwriter = new ISOEncodingStringWriter();
var serializer = new XmlSerializer(typeof(T));
var xns = new XmlSerializerNamespaces();
xns.Add(string.Empty, string.Empty);
serializer.Serialize(stringwriter, dataToSerialize, xns);
return stringwriter.ToString();
}
catch
{
throw;
}
}
public static T Deserialize<T>(string xmlText)
{
try
{
var stringReader = new System.IO.StringReader(xmlText);
var serializer = new XmlSerializer(typeof(T));
return (T)serializer.Deserialize(stringReader);
}
catch
{
throw;
}
}
Make the following Class where you give the following attributes
[XmlRoot(ElementName = "Members", Namespace = "")]
public class Members
{
[XmlElement("Member")]
public Member[] member { get; set; }
}
public class Member
{
[XmlElementAttribute("Name")]
public string Name { get; set; }
[XmlElementAttribute("Status")]
public string Status { get; set; }
}
Then deserialize your data.
Members result = Deserialize<Members>(XML_String);
You got your members in a array and you ca convert that to a list if you want.

You can use LINQ
XElement xml = XElement.Load("locationToYourXmlFile");
var members = xml.Elements("member");
var list = members.Where(member => member.Element("status")?.Value == "Gold")
.Select(member => member.Element("name")?.Value)
.ToList();
Assuming your XML has a bunch of member elements under the root memberlist element, each with a name and status element inside that.
<?xml version="1.0" encoding="utf-8"?>
<memberlist>
<member>
<name>John</name>
<status>Gold</status>
</member>
<member>
<name>Sam</name>
<status>Silver</status>
</member>
<member>
<name>Sara</name>
<status>Gold</status>
</member>
</memberlist>

Related

c# Generate XML document based on Xpath

I need to create an XML document like this:
<Root>
<Data>
<Name>Name1</Name>
<Surname>Surname1</Surname>
<Gender>M</Gender>
</Data>
<Data>
<Name>Name2</Name>
<Surname>Surname2</Surname>
<Gender>F</Gender>
</Data>
</Root>
I've got the Xpath of the XML Elements, so I've create the following class
class XpathFieldValue
{
public string Xpath { get; set; }
public string Value { get; set; }
}
and then the following method
public static void CreateXml()
{
List<XpathFieldValue> fieldValues = new List<XpathFieldValue> {
new XpathFieldValue{ Xpath="/Root/Data/Name", Value="Name1" },
new XpathFieldValue{ Xpath="/Root/Data/Surname", Value="Surname1" },
new XpathFieldValue{ Xpath="/Root/Data/Gender", Value="M"},
new XpathFieldValue{ Xpath="/Root/Data/Name", Value="Name2" },
new XpathFieldValue{ Xpath="/Root/Data/Surname", Value="Surname2" },
new XpathFieldValue{ Xpath="/Root/Data/Gender", Value="F"}
};
XmlDocument document = new XmlDocument();
document.LoadXml("<Root/>");
foreach (XpathFieldValue fieldValue in fieldValues)
{
Set(document, fieldValue.Xpath, fieldValue.Value);
}
document.Save(#"C:\Temp\xmlDocOut.xml");
}
I've copyed the Set method from here: link
But when I run it it creates only the last parth of XML
<Root>
<Data>
<Name>Name2</Name>
<Surname>Surname2</Surname>
<Gender>F</Gender>
</Data>
</Root>
Can anyone help me?
XPath isn't really intended to generate documents but to access em.
Another (probably better) approach would be to serialize it.
But, since the question requires the fields of xml to be variable, serialization isn't a viable way. i STRONGLY advise you to change this requirement and you'll see why in the following example:
using System;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
using (var writer = new System.IO.StreamWriter(#"C:\Users\luigi.trabacchin\Desktop\asd.xml"))
{
var doc = new System.Xml.XmlDocument();
var root = doc.CreateElement("Root");
doc.AppendChild(root);
for (var i = 0; i <= 1; i++)
{
var dataNode = doc.CreateElement("Data");
root.AppendChild(dataNode);
{
var node = doc.CreateElement("Name");
dataNode.AppendChild(node);
var text = doc.CreateTextNode($"Name {i}");
node.AppendChild(text);
}
{
var node = doc.CreateElement("Surname");
dataNode.AppendChild(node);
var text = doc.CreateTextNode($"Surname {i}");
node.AppendChild(text);
}
{
var node = doc.CreateElement("Gender");
dataNode.AppendChild(node);
var text = doc.CreateTextNode(i %2 == 0 ? "M" : "F");
node.AppendChild(text);
}
}
doc.Save(writer);
}
Console.WriteLine("Hello World!");
}
}
}
It quickly becomes very tedious and hard to work with.
Still i hope this answer your question.
Next time, maybe, state all the requirements directly in the question!

List of object array from XML

I have a xml that looks like this
<?xml version="1.0" encoding="utf-8" ?>
<Resorces>
<Resource id="3" name="loreum ipsum" downloadcount="5"></Resource>
<Resource id="2" name="loreum ipsum" downloadcount="9"></Resource>
</Resorces>
I have a class
public class Report
{
public int ResourceId {get; set; }
public string ResourceName { get; set; }
public int DownloadCount { get; set; }
}
I want to convert that xml into list of Report objects
I tried the below code
var resourceList = doc.Descendants("Resorces")
.First()
.Elements("Resource")
.ToList();
I get values like this,
How can I get it as list of objects?
Basically what you are missing is the part where you convert the Xml objects into your defined object of Report. This is how you can do it:
var resourceList = doc.Descendants("Resorces")
.First()
.Elements("Resource")
.Select(element => new Report()
{
ResourceId = (int)element.Attribute("id"),
ResourceName = (string)element.Attribute("name"),
DownloadCount = (int)element.Attribute("downloadcount")
})
.ToList();
I kept here the previous linq methods you called to keep it close to the original but as others said you can just get the Elements("Resource") from the doc root
XmlDocument newdoc = new XmlDocument();
newdoc.InnerXml = " <?xml version="1.0" encoding="utf-8" ?>
<Resorces>
<Resource id="3" name="loreum ipsum" downloadcount="5"></Resource>
<Resource id="2" name="loreum ipsum" downloadcount="9"></Resource>
</Resorces>";
List<string> list = new List <string>();
var selectnode = "Resorces/Resource";
var nodes = newdoc.SelectNodes(selectnode);
foreach (XmlNode nod in nodes)
{
string id = nod["id"].InnerText;
string name = nod["name"].InnerText;
string downloadcount = nod["downloadcount"].InnerText;
list.Add(id);
list.Add(name);
list.Add(downloadcount);
}
Console.WriteLine(list.Count);
You could use Elements method to get elements for a given element name.
XDocument doc = XDocument.Load(filepath);
var result = doc.Root
.Elements("Resource")
.Select(x=> new Report()
{
ResourceId = int.Parse( x.Attribute("id").Value),
ResourceName = (string)x.Attribute("name").Value,
DownloadCount = int.Parse( x.Attribute("downloadcount").Value)
})
.ToList();
Check this Demo
You can get by this
XDocument doc = XDocument.Load(xmlpath);
List<Report> resourceList = doc.Descendants("Resorces")
.First()
.Elements("Resource")
.Select(report => new Report()
{
ResourceId = (int)report.Attribute("id"),
ResourceName = (string)report.Attribute("name"),
DownloadCount = (int)report.Attribute("downloadcount")
}).ToList();

C#: How to shorten that XML appending?

I have that XML file which looks like this:
<?xml version="1.0" encoding="utf-8"?>
<backupatmail>
<backup id="0">
<foldername>TestFolder</foldername>
<backupdate>09/10/2015</backupdate>
<comment>Sample comment text is here</comment>
<numberofparts>7</numberofparts>
<lastsucceed>Test.007</lastsucceed>
</backup>
<backup id="1">
<foldername>TestFolder2</foldername>
<backupdate>09/10/2015</backupdate>
<comment>Sample comment text is here</comment>
<numberofparts>15</numberofparts>
<lastsucceed>Test.015</lastsucceed>
</backup>
</backupatmail>
Now, I want to append new node(?):
<backup id="999">
<foldername>testing1</foldername>
<backupdate>99/99/9999</backupdate>
</backup>
I wrote following code:
public static void AddBackupToXML()
{
XmlDocument doc = new XmlDocument();
doc.Load(GlobalSettings.appDefaultFolder + "backups.xml");
XmlElement backupNodeNew = doc.CreateElement("backup");
XmlAttribute backupId = doc.CreateAttribute("id");
backupId.Value = "999";
backupNodeNew.Attributes.Append(backupId);
XmlNode nodeTitle = doc.CreateElement("foldername");
nodeTitle.InnerText = "testing1";
XmlNode nodeUrl = doc.CreateElement("backupdate");
nodeUrl.InnerText = "99/99/9999";
backupNodeNew.AppendChild(nodeTitle);
backupNodeNew.AppendChild(nodeUrl);
doc.DocumentElement.AppendChild(backupNodeNew);
doc.Save(GlobalSettings.appDefaultFolder + "backups.xml");
}
Is there any shorten way to do that and also keep simplicity at beginners level?
I will recommend you to use LINQ to XML. It has more simple API for working with XML and your code will look like
var file_name = GlobalSettings.appDefaultFolder + "backups.xml";
XDocument xdoc = XDocument.Load(file_name);
var backup999 = new XElement("backup",
new XAttribute("id", 999),
new XElement("foldername", "testing1"),
new XElement("backupdate", "99/99/9999")
);
xdoc.Root.Add(backup999);
xdoc.Save(file_name);
How I did it plenty of times, using copy special feature of visual studio http://blog.codeinside.eu/2014/09/08/Visual-Studio-2013-Paste-Special-JSON-And-Xml/ I generated the classed describing the xml structure, handle it really clean and easy from code and transfomed when required with System.Xml.Serialization https://support.microsoft.com/en-us/kb/815813 in xml doc or whatever was the need.
The same way from xml to c# object https://msdn.microsoft.com/en-us/library/fa420a9y(v=vs.110).aspx.
My personal preference is to not use the xml api directly. Rather, use the model object then serialize and de-serialize it. It's much cleaner in my opinion and the code to do what you actually need is only 3 lines once your have the generic serializer in place.
What you can do is de-serialize your object into an actual "backupatmail" object and then call backupatmail.BackUpItems.Add(your new item here) and then deserialize it back into a string.
This approach is slower than using LinqToXml during runtime but most of the time a extra millisecond or more isn't a big deal.
Here's the serialization/ deserialization code.
using System.Xml;
using System.Xml.Serialization;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
public class SerializationUtils
{
public static T Deserialize<T>(string data)
{
XmlSerializer objSerializer = new XmlSerializer(typeof(T));
using (var reader = new StringReader(data))
{
return (T)objSerializer.Deserialize(reader);
}
}
public static string Serialize<T>(T obj)
{
XmlSerializer objSerializer = new XmlSerializer(typeof(T));
XmlSerializerNamespaces emptyNamespaces = new XmlSerializerNamespaces(new [] { XmlQualifiedName.Empty });
var settings = new XmlWriterSettings();
settings.OmitXmlDeclaration = true;
settings.ConformanceLevel = ConformanceLevel.Auto;
#if DEBUG
settings.Indent = true;
#else
settings.Indent = false;
#endif
using (var stream = new StringWriter())
using (var writer = XmlWriter.Create(stream, settings))
{
objSerializer.Serialize(writer, obj, emptyNamespaces);
return stream.ToString();
}
}
}
and for your use.
string mailItems = GetXmlStringFromSomewhere();
var objMail = SerializationUtils.Deserialize<BackUpMail>(mailItems);
var newItem = new BackUp() { FolderName = "testing1", BackupDate = DateTime.Now};
objMail.BackUpItems.Add(newItem);
var strMailWAddedItem = SerializationUtils.Serialize(objMail);
Here are your entity classes.
public class BackUpMail
{
public List<BackUp> BackUpItems {get;set;}
}
public class BackUp
{
[XmlAttribute("id")]
public string ID {get;set}
[XmlElement("foldername")]
public string FolderName {get;set;}
[XmlElement("backupdate")]
public DateTime BackupDate {get;set;}
[XmlElement("comment")]
public string Comment {get;set}
[XmlElement("numberofparts")]
public string NumberOfParts {get;set}
[XmlElement("lastsucceed")]
public string LastSucceed {get;set}
}
Since you have the code, just parameterize it.
public static void someOtherMethod(){
XmlDocument doc = new XmlDocument();
doc.Load(GlobalSettings.appDefaultFolder + "backups.xml");
// some loop..
doc.DocumentElement.AppendChild(createNode(id[i], foldername[i], backupdate[i]));
doc.Save(GlobalSettings.appDefaultFolder + "backups.xml");
}
public static void createNode(string id, string foldername, string backupdate)
{
XmlElement backupNodeNew = doc.CreateElement("backup");
XmlAttribute backupId = doc.CreateAttribute("id");
backupId.Value = id;
backupNodeNew.Attributes.Append(backupId);
XmlNode nodeTitle = doc.CreateElement("foldername");
nodeTitle.InnerText = foldername;
XmlNode nodeUrl = doc.CreateElement("backupdate");
nodeUrl.InnerText = backupdate;
backupNodeNew.AppendChild(nodeTitle);
backupNodeNew.AppendChild(nodeUrl);
return backupNodeNew;
}

Can I add a prefix to root element when I have no control over the serialized .NET type?

I have a library that contains a .NET type. The library has its own configuration (annotations etc) for serializing the type to XML, and I do not have the source code.
No matter what I do, I could not manage to add the prefix I want to add to the root element of the output XML. Using XmlSerializerNamespaces made no difference. Here is a snippet that shows my code at the moment:
var comp = row[0] as LibraryType;
var ser = new XmlSerializer(comp.GetType());
var strWriter = new StringWriter();
var xmlWriter = XmlWriter.Create(strWriter);
ser.Serialize(xmlWriter, comp);
string serXml = strWriter.ToString();
Is there a way in configure XMLSerializer to create an xlm output for root such as
<lt:LibraryType ....
instead of the current
<LibraryType .....
I'm getting ?
Lets say that your library type looks like
public class Foo
{
public int i { get; set; }
}
public class Bar
{
public Foo Foo { get; set; }
}
then serialization should look like
var comp = new Bar {Foo = new Foo()};
var overrides = new XmlAttributeOverrides();
overrides.Add(typeof (Bar), new XmlAttributes {XmlRoot = new XmlRootAttribute {Namespace = "http://tempuri.org"}});
// in case you want to remove prefix from members
var emptyNsAttribute = new XmlAttributes();
emptyNsAttribute.XmlElements.Add(new XmlElementAttribute { Namespace = "" });
overrides.Add(typeof(Bar), "Foo", emptyNsAttribute);
// if you actual library type contains more members, then you have to list all of them
var ser = new XmlSerializer(comp.GetType(), overrides);
var strWriter = new StringWriter();
var xmlWriter = XmlWriter.Create(strWriter);
var ns = new XmlSerializerNamespaces();
ns.Add("lt", "http://tempuri.org");
ser.Serialize(xmlWriter, comp, ns);
string serXml = strWriter.ToString();
and the output will be
<?xml version="1.0" encoding="utf-16"?><lt:Bar xmlns:lt="http://tempuri.org"><Foo><i>0</i></Foo></lt:Bar>

How to convert JSON to XML or XML to JSON?

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;
}

Categories