XDocument to JSON, JsonProperties - c#

I am working with C# (ASP.Net, MVC) and Newtonsoft for JSON serialization. I get an XDocument like the one below which I would like to have in JSON format, for the view.
<group>
<name>Group 1</name>
<description><p>Description</p></description>
<section>
..
</section>
<section>
..
</section>
</group>
I have an Extension like this
private static readonly JsonSerializer jSerializer = JsonSerializer.Create(new JsonSerializerSettings {});
public static string ToJson(this object obj) {
using (StringWriter writer = new StringWriter()) {
jSerializer.Serialize(writer, obj);
return writer.ToString();
}
}
The problem now is, that the description gets deserialized, so I have something like
... "description": { "p": "Description Text" }
which will be displayed as "[Object object]" when just posted as is.
Is there a way to set some JsonProperties for the XDocument (in general), without generating a completely deserialized class?
If not, is there a way to set some JsonProperty saying "Keep this as string, do not serialize any further"
If I were to use an XSD generated class for this, what "type" would I need to set? "anyType"?
Help would be appreciated,
Best regards.

I am adding this answer due to it's google search rank when looking up "c# convert xml to json XDocument".
string json = JsonConvert.SerializeXNode(xDocument);
This answer uses the more modern XNode vs XmlNode

Using Json.NET you can serialize an XML node directly to JSON using the following line:
string json = JsonConvert.SerializeXmlNode(xmlNode);
To convert your XDocument to XmlDocument see this question:
Converting XDocument to XmlDocument and vice versa
You can then use your converted XmlDocument as parameter for SerializeXmlNode() because it inherits from XmlNode.

Related

Modifying element of Json string (in C#)

I'm trying to modify an attribute of an XML string using Json in C#. Currently I'm doing the following:
XmlDocument serializedFormXml = new XmlDocument();
serializedFormXml.LoadXml(mySerializedForm);
string formJsonString = JsonConvert.SerializeXmlNode(serializedFormXml, Newtonsoft.Json.Formatting.None, true);
JObject formJsonObj = JObject.Parse(formJsonString);
formJsonObj["#code"] = "myNewValue";
var xml = JsonConvert.DeserializeXmlNode(formJsonObj.ToString()).ToString();
When I do this I get get an exception on the last line:
Unable to cast object of type 'Newtonsoft.Json.Converters.XmlDocumentWrapper' to type 'Newtonsoft.Json.Converters.IXmlElement'
Any ideas what I'm doing wrong and how I can fix modify my form attribute "code"?
This is the XML I'm using:
<Form code="XYZ">
<Info>Data</Info>
.....
Thanks!
That's going to be way, way easier with Linq-to-XML:
var doc = XDocument.Parse(mySerializedForm);
doc.Root.SetAttributeValue(doc.Root.Name.Namespace + "code", "myNewValue");
var xml = doc.ToString();
This drops the XML declaration. If you need the XML declaration included, you can use the following extension method:
public static class XObjectExtensions
{
public static string ToXml(this XDocument xDoc)
{
using (var writer = new StringWriter())
{
xDoc.Save(writer);
return writer.ToString();
}
}
}
And then write:
var xml = doc.ToXml();
If specifically you need to make the encoding string say "UTF-8", use Utf8StringWriter from this answer.
Update
The reason you code fails is that you stripped the XML root element name away when you converted to json by passing true here:
string formJsonString = JsonConvert.SerializeXmlNode(serializedFormXml, Newtonsoft.Json.Formatting.None, true);
Thus you need to add it back when converting back:
var xml = JsonConvert.DeserializeXmlNode(formJsonObj.ToString(), serializedFormXml.DocumentElement.Name).ToString();

Getting unexpected result when adding json:Array attribute to an xml node before serializing

I have an XML document that I need to serialize into JSON. I had everything working (or so I thought) until my handlebars.js was failing on the "each" expression. I have narrowed the problem down to my xml > json conversion using JSON.NET. Elements that can sometimes have multiple children are rendering as single elements (not arrays) when converting to json. The documentation states that I have to add an attribute to the node (json:Array="true") for it to always render as an array (which would no longer break my handlebars).
The first thing I do is add the namespace to my XML document (http://james.newtonking.com/projects/json).
Then I am iterating through each node and testing it to see if its one that I need to be array'd then add the attribute.
//Pseudo code
foreach(XmlNode node in list)
{
XmlAttribute attr = originalDoc.CreateAttribute(#"json:Array");
if(node.Name == "needsToBeAnArray")
{
node.Attributes.Append(attr);
}
}
I then save the doc to a memory stream and reload it into a new XmlDocument object.
The resulting json I am getting however looks like this:
{"#Array":"true","item":[{"subitem":"foo", "subitem2":"foo2"}]}
From my understanding of the JSON.NET docs, it should just render as an array (not show this "#Array" thing). Does anyone have and experience with this problem?
It seems that the json prefix is getting stripped off the json:Array attribute when you add it to the node, since it is not qualified with a namespace. Without the json prefix, the attribute has no special meaning to Json.Net; thus, it gets written into the JSON instead of changing the output behavior.
Try it like this instead:
string xml =
#"<person>
<name>Joe</name>
<age>28</age>
<role>Admin</role>
</person>";
XmlDocument doc = new XmlDocument();
doc.LoadXml(xml);
foreach (XmlNode node in doc.DocumentElement.ChildNodes)
{
if (node.Name == "role")
{
XmlAttribute att = doc.CreateAttribute("json", "Array", "http://james.newtonking.com/projects/json");
att.Value = "true";
node.Attributes.Append(att);
}
}
string json = JsonConvert.SerializeXmlNode(doc);
Console.WriteLine(json);
Output:
{
"person": {
"name": "Joe",
"age": "28",
"role": [
"Admin"
]
}
}
So I figured out what I was doing wrong if anyone is interested. When I was creating the attribute:
XmlAttribute attr = originalDoc.CreateAttribute(#"json:Array");
I was trying to name it with my prefix. The proper way to do this is to pass in the prefix, name and namespace as the parameters.
XmlAttribute attr = doc.CreateAttribute("json", "Array", "http://james.newtonking.com/projects/json");

Convert List<Object> to XML

I have a very simple application. MainUI has the List of CustomClass. I pass this list to WCF service. WCF Service further needs to save these objects in database.
I am using Open XML in our sql stored procedure to get better performnace. But i don't know how to convert my List of Objects to XML.
If i have a datatable, it'll be easy as datatables have methods to get the XML out of them. But how to use for List of objects.
I completly understand that if my List is coming over the WCF, it is getting serialized properly. But what should i exactly need to do.
IMO, look into Controlling XML Serialization with Attributes and the XmlSerializer class and possibly create container classes parallel to your CustomClass. While List<> can't be automatically serialized by the default XML serializer, an array can be.
Thera are two ways: use XmlSerializer or DataContractSerializer.
Code for convert list to xml : List name GridDetails
void ConvertToXml()
{
string xmlString = ConvertObjectToXMLString(GridDetails);
// Save C# class object into Xml file
XElement xElement = XElement.Parse(xmlString);
xElement.Save(#"C:\Users\user\Downloads\userDetail.xml");
}
static string ConvertObjectToXMLString(object classObject)
{
string xmlString = null;
XmlSerializer xmlSerializer = new XmlSerializer(classObject.GetType());
using (MemoryStream memoryStream = new MemoryStream())
{
xmlSerializer.Serialize(memoryStream, classObject);
memoryStream.Position = 0;
xmlString = new StreamReader(memoryStream).ReadToEnd();
}
return xmlString;
}

(don't ?) use JavaScriptSerializer to convert xml file (of unknown schema) to json in c#

Is JavascriptSerializer the "tool" to convert an xml file (of unknown schema) into a json string ?
There are some threads here dealing about how to convert xml to json in c#.
And some recommended dedicated solutions (http://www.phdcc.com/xml2json.htm)
But in those threads there are always one suggesting using JavaScriptSerializer. But there is never clear explanation on how to do it. One always elude it or start with an object instead of an xml.
To make it clear :
I don't look after having my xml turned into objects.
If I can, I'd prefer to avoid it.
XML => Json would please me more than XML => objects => Json.
But everybody is telling don't reinvent wheel use JavaScriptSerializer. But I don't feel like this is the way to go. Setting up objects from xml looks like a terrible task (strongly typing).
So my question is :
Should I stay with the quick (but "dirty") methods described in http://www.phdcc.com/xml2json.htm
Or
Could I use JavascriptSerializer even if I don't know the schema of the xml ?
If so please fill in the gaps/modify the following code
namespace ExtensionMethods {
public static class JSONHelper
{
public static string ToJSON(this XmlDocument doc)
{
object obj = get_An_Object_From_My_XML_Without_Too_Much_Hassle_Like_Having_To_Deal_With_Strongly_Type(doc); // how to do that ???
JavaScriptSerializer serializer = new JavaScriptSerializer();
return serializer.Serialize(obj);
}
}
}
using ExtensionMethods;
...
XmlDocument mydoc = new XmlDocument(#"c:\test.xml");
Response.write(mydoc.ToJSON());
I think you could use json.net in order to receive a unknown xml into a json object:
string xml = #"<?xml version=""1.0"" standalone=""no""?>
<root>
<person id=""1"">
<name>Alan</name>
<url>http://www.google.com</url>
</person>
<person id=""2"">
<name>Louis</name>
<url>http://www.yahoo.com</url>
</person>
</root>";
XmlDocument doc = new XmlDocument();
doc.LoadXml(xml);
string jsonText = JsonConvert.SerializeXmlNode(doc);
//{
// "?xml": {
// "#version": "1.0",
// "#standalone": "no"
// },
// "root": {
// "person": [
// {
// "#id": "1",
// "name": "Alan",
// "url": "http://www.google.com"
// },
// {
// "#id": "2",
// "name": "Louis",
// "url": "http://www.yahoo.com"
// }
// ]
// }
//}

XML Serialization in C# without XML attribute nodes

I have an XML document format from a legacy system that I have to support in a future application. I want to be able to both serialize and deserialize the XML between XML and C# objects, however, using the objects generated by xsd.exe, the C# serialization includes the xmlns:xsi..., xsi:... etc XML attributes on the root element of the document that gets generated. Is there anyway to disable this so that absolutely no XML attribute nodes get put out in the resulting XML ? The XML document should be elements only.
Duplicate? XmlSerializer: remove unnecessary xsi and xsd namespaces
Yes, use the XmlSerializerNamespaces class.
Example:
var s= new System.Xml.Serialization.XmlSerializer(typeof(TypeToSerialize));
var ns= new System.Xml.Serialization.XmlSerializerNamespaces();
ns.Add( "", "");
System.IO.StreamWriter writer= System.IO.File.CreateText(filePath);
s.Serialize(writer, objectToSerialize, ns);
writer.Close();
See also: XmlSerializer: remove unnecessary xsi and xsd namespaces
There is no way to force XML Serializer to ignore xsi attributes (unless you implement IXmlSerializable and force custom serialization or use XmlAttributeOverrides). However the only time xsi: attributes show up is when you have a nullable element. If you do need to use nullable elements you can of course post-process the XML to remove all xsi: occurences. However if you do this think about how you will deserialize the XML back into an object, if xsi:nil is missing on an element and the element is defined as a nullable integer you will run into an exception.
#Cheeso, please correct me if i am wrong.
I have the following code.
public class TestSer
{
public int? MyProperty { get; set; }
}
TestSer ser = new TestSer();
ser.MyProperty = null;
StringBuilder bldr = new StringBuilder();
var ns = new System.Xml.Serialization.XmlSerializerNamespaces();
ns.Add("", "");
XmlSerializer s = new XmlSerializer(typeof(TestSer));
using (StringWriter writer = new StringWriter(bldr))
{
s.Serialize(writer, ser, ns);
}
I get the following output.
<?xml version="1.0" encoding="utf-16"?>
<TestSer>
<MyProperty d2p1:nil="true" xmlns:d2p1="http://www.w3.org/2001/XMLSchema-instance" />
</TestSer>
This isn't exactly element only as the question asks for.

Categories

Resources