Check whether JSON property contains value or array - c#

I have a random input XML file which I am trying to convert into JSON and access values. Now JSON might have a simple JSON object or it might have array within it. When I am working with simple JSON object I am able to get values properly but when any JSON property contains an array I am getting an error that "value cannot be null". I am using newtonsoft library for this. My question is how to know whether a property is having a value or an array in JSON when every time the input file might have different structure. I hope I am able to explain my problem and the code I am using is given below:
XmlDocument Xmldoc = new XmlDocument();
Xmldoc.LoadXml(fileContents);
string root = Xmldoc.DocumentElement.Name;
var json = JsonConvert.SerializeXmlNode(Xmldoc);
var JsonStringObject = (JObject)JsonConvert.DeserializeObject(json);
var XMLNodesData = JsonStringObject[root.ToString()].Children();
List<JToken> tokens = XMLNodesData.Children().Children().ToList();
foreach (var node in tokens)
{
foreach (Field field in fields)
{
var inputString = node[field.FieldName].Value<string>();
}
}
With above code I am able to get value properly on inputString if I am having a simple XML such as :
<PatientRecords>
<Patient>
<firstname>John</firstname>
<lastname>Smith</lastname>
<patientid>111</patientid>
<dob>2022-05-13</dob>
</Patient>
<Patient>
<firstname>Martha</firstname>
<lastname>Stewart</lastname>
<patientid>112</patientid>
<dob>2022-04-14</dob>
</Patient>
</PatientRecords>
but if I Change XML to below given format then I am getting an error "Value cannot be null" incase of age property:
<PatientRecords>
<Patient>
<firstname>John</firstname>
<lastname>Smith</lastname>
<patientid>111</patientid>
<age>
<dob>2022-05-13</dob>
</age>
</Patient>
<Patient>
<firstname>Martha</firstname>
<lastname>Stewart</lastname>
<patientid>112</patientid>
<age>
<dob>2022-04-14</dob>
</age>
</Patient>
</PatientRecords>
Note: field.Fieldname is used to get tag name ("firstname", "lastname" etc) from a different XML which is required in my project. Please help regarding this and thank you in advance.

You can try below
var jsonResult = JsonConvert.DeserializeObject<dynamic>(jsonStr);
if(jsonResult.Type==JTokenType.Object)
{
//JSON contains Object
}
else if(jsonResult.Type==JTokenType.Array)
{
//JSON contains Array
}

Related

Convert Soap XML to a Json Object in C#

Background Information
I have two .net services (say A and B). Service B uses a service reference of Service A. Here, 'basicHttpBinding' is being used.
There is a global.asax.cs present in Service A where I plan to perform some operations before the call is sent to Service A.svc.cs
I'm able to read request body in global.asax.cs using the following code.
StreamReader streamReader = new StreamReader(HttpContext.Current.Request.InputStream);
streamReader.BaseStream.Position = 0;
string message = streamReader.ReadToEnd();
The 'message' string variable holds the request body i.e. payload in xml format. I'm able to read the xml using the following code.
XmlDocument doc = new XmlDocument();
doc.LoadXml(message);
The xml looks like this
<?xml version="1.0" encoding="UTF-8"?>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<FunctionName xmlns="http://tempuri.org/">
<sampleString>value</sampleString>
<sampleObject xmlns:a="http://schemas.datacontract.org/2004/07/contract" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<a:sampleProperty1>value1</a:sampleProperty1>
<a:sampleProperty2>value2</a:sampleProperty2>
</sampleObject>
</FunctionName>
</s:Body>
</s:Envelope>
Question
Is there any way to convert this xml to json? I'm only interested in the data inside in the xml.
Bonus Question
What does 'a:' in 'a:sampleProperty' mean / stand for?
Desired Output
The final json should like this
{
"sampleString": "value",
"sampleObject": {
"sampleProperty1": "value1",
"sampleProperty2": "value2"
}
}
Things that I have tried
I have tried removing top parent nodes and their attributes using code. Then, I used to JsonConvert to convert xml to json
JsonConvert.SerializeXmlNode(doc.ChildNodes[0].ChildNodes[0].ChildNodes[0], Newtonsoft.Json.Formatting.None, true);
Doing this only helped me partially and I ended with the following json output
{
"sampleString": "value",
"sampleObject": {
"#xmlns:a":"http://schemas.datacontract.org/2004/07/contract",
"#xmlns:i":"http://www.w3.org/2001/XMLSchema-instance",
"a:sampleProperty1": "value1",
"a:sampleProperty2": "value2"
}
}
See the accepted answer here to remove the namespaces from the XML, Define a method RemoveAllNamespaces and change the code like below -
XElement xmlDocumentWithoutNs = RemoveAllNamespaces(XElement.Parse(message));
var xmlWithoutNs = xmlDocumentWithoutNs.ToString();
/* OUTPUT
<Envelope>
<Body>
<FunctionName>
<sampleString> value </sampleString>
<sampleObject>
<sampleProperty1> value1 </sampleProperty1>
<sampleProperty2> value2 </sampleProperty2>
</sampleObject>
</FunctionName>
</Body>
</Envelope>
*/
var json =JsonConvert.SerializeXmlNode(doc.ChildNodes[0].ChildNodes[0].ChildNodes[0], Newtonsoft.Json.Formatting.None, true);
XmlDocument doc = new XmlDocument();
doc.LoadXml(xmlWithoutNs);
/* OUTPUT
{
"sampleString":" value ",
"sampleObject":{
"sampleProperty1":" value1 ",
"sampleProperty2":" value2 "
}
}
*/
To answer your question -
What does 'a:' in 'a:sampleProperty' mean / stand for?
A colon (:) in a tag or attribute name means that the element or attribute is in an XML namespace.The colon, and the part before it, aren't really part of the tag / attribute name, they just indicate which namespace it's in.
https://en.wikipedia.org/wiki/XML_namespace
Discussions here

Store and Display xml values in MessageBox

<?xml version="1.0" standalone="yes"?>
<Subject>
<Book>
<Name>ASP.NET</Name>
<Author>ABC</Author>
<Published>2018</Published>
<Price>$100</Price>
</Book>
</Subject>
Above is the xml file i have. I want to store xml nodes and values using Dictionary or Collections in C# and display those on message box using winforms.
Output should be as:
Name: ASP.NET
Author: ABC
Published: 2018
Price: $100
I have tried the following but getting lots of errors...
var doc = XDocument.Load(#"xmlfile.xml");
var rootNodes = doc.Root.DescendantNodes().OfType<XElement>();
var keyValuePairs = from n in rootNodes
select new
{
TagName = n.Name,
TagValue = n.Value
};
var allitems = new Dictionary<string, string>();
foreach (var node in rootNodes)
{
allitems.Add(node.Name.ToString(), node.Value);
//string str = string.Join("",allitems);
MessageBox.Show(allitems);
}
You should first parse the XML into objects (Convert XML String to Object).
Then you can simply implement the ToString() method of that type, to print it up nicely.
I think for this part, you need to convert it into .cs file and XML cannot retrieve the messagebox...
Inside of the .cs file, you also can try to put the code for messagebox
MessageBox.Show( // put something over there and you want to show this output );

LINQ TO XML retrieving Child Element Value

I have the following XML
<ABC xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://ns.hr-xml.org/2007-04-15">
<ReceiptId>
<IdValue>123</IdValue>
</ReceiptId>
<ClientOrderId>
<IdValue>345</IdValue>
</ClientOrderId>
<AccessPoint>
<Description>My Description</Description>
</AccessPoint>
<ABCStatus>
<Status>Error</Status>
<Details>ERRORS:
Talent is already in an active process for this opening.
</Details>
<StatusDate>2015-08-05</StatusDate>
</ABCStatus>
</ABC>
I am trying to retrieve the element value 345 nested in IdValue and ClientOrderId
I have used the Linq to xml code in C# to retrieve the value with no luck
XDocument XMLResults = XDocument.Parse(sResult);
var sClientOrderID =
from nodeAElem in XMLResults.Root.Elements("ABC")
from nodeA1Elem in nodeAElem.Elements("ClientOrderId")
from nodeA11Elem in nodeA1Elem.Elements("IdValue")
select nodeA11Elem.Value;
also need to retrieve the Status Elements value which is Error for the above xml.
Any help is greatly appreciated
Your XML document is using a namespace, you have to use it in your query to make it work.
Root already brings you to ABC element, so you don't have to call Elements("ABC")
You're looking for single value, so you probably want to use Element instead of Elements.
var ns = (XNamespace)"http://ns.hr-xml.org/2007-04-15";
var sClientOrderID = (int)XMLResults.Root
.Element(ns + "ClientOrderId")
.Element(ns + "IdValue");

JsonConvert.DeserializeXmlNode - must begin with an object

I'm getting a JsonSerializationException calling DeserializeXmlNode() on JSON data that starts with [[ (i.e. it's an array of arrays).
What is the best
way to turn this into XML?
Are there any other JSON schemas that can't be turned into XML?
Update: How the XML should appear is an interesting question. Having an array of arrays means there is no root node (that's an easy one - insert ) but also the set of children nodes have no name. I'm not sure what makes sense here. And this may be a deal killer for using XPath on JSON. So on this part too, any suggestions?
Update 2 - the JSON data:
[["P0010001","NAME","state"],
["4779736","Alabama","01"],
["710231","Alaska","02"],
["6392017","Arizona","04"],
["2915918","Arkansas","05"],
["37253956","California","06"],
["5029196","Colorado","08"],
["3574097","Connecticut","09"],
["897934","Delaware","10"],
["601723","District of Columbia","11"],
["18801310","Florida","12"],
["9687653","Georgia","13"],
["1360301","Hawaii","15"],
["1567582","Idaho","16"],
["12830632","Illinois","17"],
["6483802","Indiana","18"],
["3046355","Iowa","19"],
["2853118","Kansas","20"],
["4339367","Kentucky","21"],
["4533372","Louisiana","22"],
["1328361","Maine","23"],
["5773552","Maryland","24"],
["6547629","Massachusetts","25"],
["9883640","Michigan","26"],
["5303925","Minnesota","27"],
["2967297","Mississippi","28"],
["5988927","Missouri","29"],
["989415","Montana","30"],
["1826341","Nebraska","31"],
["2700551","Nevada","32"],
["1316470","New Hampshire","33"],
["8791894","New Jersey","34"],
["2059179","New Mexico","35"],
["19378102","New York","36"],
["9535483","North Carolina","37"],
["672591","North Dakota","38"],
["11536504","Ohio","39"],
["3751351","Oklahoma","40"],
["3831074","Oregon","41"],
["12702379","Pennsylvania","42"],
["1052567","Rhode Island","44"],
["4625364","South Carolina","45"],
["814180","South Dakota","46"],
["6346105","Tennessee","47"],
["25145561","Texas","48"],
["2763885","Utah","49"],
["625741","Vermont","50"],
["8001024","Virginia","51"],
["6724540","Washington","53"],
["1852994","West Virginia","54"],
["5686986","Wisconsin","55"],
["563626","Wyoming","56"],
["3725789","Puerto Rico","72"]]
I had an array of objects, shaped like:
[{foo:bar}, {foo:bar2}]
...What I did to work around this problem is to wrap the text first like so:
public XmlDocument JsonArrayToXml(string json)
{
var wrappedDocument = string.Format("{{ item: {0} }}", json);
var xDocument = JsonConvert.DeserializeXmlNode(wrappedDocument, "collection");
return xDocument;
}
This does not throw an error. The shape of the XML resembles:
<?xml version="1.0" encoding="UTF-8"?>
<collection>
<item>
<foo>bar</foo>
</item>
<item>
<foo>bar2</foo>
</item>
</collection>

Load info from xml, save related (changed) info using c#

Friends,
My school project is having an xml data file:
<patients>
<patient>
<regNo>2012/Mar/003</regNo>
<name>Jhon</name>
<add>Somewhere</add>
<mobile>0000</mobile>
.
.
.
<stay>2</stay>
<costofroom>100</costofroom>
<total>200</total>
</patient>
</patients>
My Windowsform "EditPatients_Load" is able to fetch all info of patient Jhon, and now let's assume that the Admin needs to change some information in the form & resubmit.
Then how to write back all values to Jhon's account in the same xml
file????
I'm not able to makeup the logical code, even if I check the node if (patients.paptient.name = "nameComboBox.text").... how to make sure that I'm writing other values on proper place?
Rgrdz,
Try this:
//string xml =
//#"<patients><patient><regNo>2012/Mar/003</regNo><name>Jhon</name><add>Somewhere
//</add><mobile>0000</mobile><stay>2</stay><costofroom>100</costofroom><total>200</total>
//</patient></patients>";
XDocument xmlDoc = XDocument.Load(#"c:\abc.xml");
var items = (from item in xmlDoc.Descendants("patient")
where item.Element("name").Value == "Jhon"
select item);
if (items.Count() > 0)
{
var item = items.First();
item.SetElementValue("add", "New New Address");
xmlDoc.Save(#"c:\abc.xml", SaveOptions.None);
}
You can get single element using
var item = (from item in xmlDoc.Descendants("patient")
where item.Element("name").Value == "Jhon"
select item).FirstOrDefault();
then update it using SetElementValue() method.
//Updated Xml
<?xml version="1.0" encoding="utf-8"?>
<patients>
<patient>
<regNo>2012/Mar/003</regNo>
<name>Jhon</name>
<add>New Address</add>
<mobile>0000</mobile>
<stay>2</stay>
<costofroom>100</costofroom>
<total>200</total>
</patient>
</patients>
Reference:
Update XML with C# using Linq
I would take the xml serialization/deserialization route to solve this:
http://support.microsoft.com/kb/815813
How to Deserialize XML document
That way you can work with objects and not have to parse xml files manually.
If you're using .NET 3.5 onward you can use the XDocument class like the following. I'm assuming your content is in a .xml file.
XDocument xdoc = XDocument.Load(#"C:\Tmp\test.xml");
//this would ensure you get the right node and set its text content/value
xdoc.Element("patients")
.Element("patient").Element("add").Value = "some new address?";
xdoc.Save(#"C:\Tmp\test.xml");
The file test.xml would change to:
<patients>
<patient>
<regNo>2012/Mar/003</regNo>
<name>Jhon</name>
<add>some new address?</add>
<mobile>0000</mobile>
<stay>2</stay>
<costofroom>100</costofroom>
<total>200</total>
</patient>
</patients>

Categories

Resources