I have the code below which takes file containing XML and JSON and deserializes the JSON/XML into objects
using (var streamReader = new StreamReader("output.json"))
{
var rawJsonToLoad = streamReader.ReadLine();
var jsonWalkOrder = rawJsonToLoad.FromJson<MeterWalkOrder>();
Debug.WriteLine(jsonWalkOrder.Dump());
}
var xml = File.ReadAllText("WalkOrder.xml");
var xmlTest = xml.LoadFromXML<MeterWalkOrder>();
JSON
{
Name: Red Route,
Meters:
[
{
__type: "WindowsFormsApplication1.Classes.Meter, WindowsFormsApplication1",
MeterID: 1,
SerialNumber: 12345
},
{
__type: "WindowsFormsApplication1.Classes.Meter, WindowsFormsApplication1",
MeterID: 2,
SerialNumber: SE
}
]
}
[
1,
441,
2
]
XML
<MeterWalkOrder>
<Name>Red Route</Name>
<Meters>
<Meter>
<MeterID>1</MeterID>
<SerialNumber>12345</SerialNumber>
</Meter>
<Meter>
<MeterID>2</MeterID>
<SerialNumber>SE</SerialNumber>
</Meter>
</Meters>
</MeterWalkOrder>
Whilst on the surface this does work fine, there is a major drawback with it, it is using extension methods that are all extending the string data type
What I really want to be able to do is to say something like
var xml = File.ReadAllText("WalkOrder.xml");
var xmlTest = new MeterWalkOrder();
xmlTest.LoadFromXML(xml);
How can this be done with an extension method that extends an object rather than string?
I dont like the current approach because there is not enough flexibility in it, it forces the creation of new objects. For example, using the current method if I had a list of 5 meters and I wanted to add another 10 meters from a string of JSON I wouldnt be able to, because the fromJson would force me to recreate my meters list so I would only have the 10 meters in the file, not those 10 + the 5 that were already in the list
Paul
Edit - Following comments I have tried an extension method which actually demonstrates my issue perfectly
public static class ObjectExtensions
{
public static T PopulateFromJson<T>(this T obj)
{
using (var streamReader = new StreamReader("output.json"))
{
var rawJsonToLoad = streamReader.ReadLine();
obj = rawJsonToLoad.FromJson<T>();
}
return obj;
}
}
If I use the code below...
var testJson = new MeterWalkOrder();
testJson.Meters.Add(new Meter() { SerialNumber = "Meter 1" });
testJson.Meters.Add(new Meter() { SerialNumber = "Meter 2" });
testJson.PopulateFromJson();
...
After PopulateFromJson I want the object to be preserved - but because fromJson returns a new object it isnt - so my object would only contain the 2 meters from the JSON file, I actually want them added to the end of the list - in short I want to use the existing object not to have a new one created
Paul
Related
for a legacy system, I need to return an object than have inside it a key value than it's the date, and inside have a body, any idea how to get the job done?
I need to return this array
{
"sellerId":"157747190185796800",
"data":
{
"2020-08-25":{ "sales":195000,"comission":25350},
"2020-08-26":{"sales":70500,"comission":9165},
"2020-08-27":{ "sales":51000,"comission":6630}
}
}
I'm trying with a json result and it works, but there's a problem with the key value date
Edit: I'm trying to make the suggestion of an dictionary, but, I don't know what I'm doing bad in this case. i try as an object too and doesn't work.
var lst = new List<Dictionary<string, JsonResult>>();
foreach (var item in listToReturn)
{
lst.Add(new Dictionary(item.DateFromStr, new JsonResult (new
{
sales = item.sales,
comission = item.Comission,
})));
}
I would create the JSON using anonymous objects, using a Dictionary for the sales data like this:
var resultToReturn = new
{
sellerId,
data = listToReturn.ToDictionary (
item => item.DateFromStr,
item => new
{
sales = item.Sales,
commission = item.Commission
}
)
};
Then you can serialize resultToReturn using your favorite serializer, or if you're using MVC, return it in a JsonResult.
Demo fiddle: https://dotnetfiddle.net/jZvoNo
Note: this solution assumes all the date values will be unique within the list, otherwise ToDictionary will throw an exception.
I need to export data into XML file, using XSD. There are many examples how to do it, but most of them do not show how to popuate the actual data, but to save the object as an XML. The one I could find didn't work for me.
1) I use an xsd file of Agresso http://services.agresso.com/schema/ABWInvoice/2011/11/14/ABWInvoice.html
which I have successfully downloaded and generated a class with xsd.exe command.
2) I have added this class to my project. ABWInvoice is the class for the complexType element Invoice. The xml may contain more than one invoice, hence its maxOccurs is set to "unbounded". Each Invoice can have InvoiceNo element and Header complex element.
3) I have started to write the code and first thought I can use a list, as the number of invoices is dynamic. But List<ABWInvoice> list = new ABWInvoice(); didn't work "Cannot implicitly convert type 'abc.Agresso.ABWInvoice' to 'System.Collections.Generic.List'", so I have decided to at least try to have one record and go from there, but oAgresso.Invoice[0].Header fails in runtime with System.NullReferenceException: 'Object reference not set to an instance of an object.'
private void CreateXMLHeader()
{
var oAgresso = new ABWInvoice { };
oAgresso.Invoice[0] = new ABWInvoiceInvoice
{ InvoiceNo = "1" };
oAgresso.Invoice[0].Header = new ABWInvoiceInvoiceHeader()
{
OrderRef = "5678",
InvoiceDate = Date.Now
};
//var agressoXMLImport = Shared.XMLHelper.ReadXml<ABWInvoice>(#"E:\temp\ABW_Invoice_Test.xml");
Shared.XMLHelper.SaveXml<ABWInvoice>(oAgresso, #"e:\temp\ABW_Export_Test.xml");
}
Can you advise on how
1) build a dynamic array (I do not know the amount of invoices, when I start building the XML;
2)What is wrong with my current code?
Much appreciated!
Member arrays need to be initialized with known size, so its easier to make a List of ABWInvoiceInvoice then populate it with your data by using add method and at the end assign whole list to your member array
private void CreateXMLHeader()
{
var oAgresso = new ABWInvoice { };
List<ABWInvoiceInvoice> invlist = new List<ABWInvoiceInvoice>();
invlist.Add(new ABWInvoiceInvoice { InvoiceNo = "1" ,
Header= new ABWInvoiceInvoiceHeader()
{
OrderRef = "5678",
InvoiceDate = DateTime.Now
}
});
oAgresso.Invoice = invlist.ToArray();
I'm trying to automate the addition of new objects to an existing JSON file. I looked all around the web but only found adding data and stuff but not a whole object. This is how the file that I want to edit looks:
[
{"id":"123","name":"carl"}
]
and I want to go to
[
{"id":"123","name":"carl"},
{"id":"1234","name":"carl2"}
]
Thank you for all your answers but I don't think everyone completely understands what i mean I have tried some of the answers but then I get this:
[
"{\"id\":\"123\",\"name\":\"carl\"}"
]"{\"id\":\"1234\",\"name\":\"carl2\"}"
and I want everything in between the [].
If you use json.NET you can simply deserialize and serialize the json.
var list = JsonConvert.DeserializeObject<List<Person>>(myJsonString);
list.Add(new Person(1234,"carl2");
var convertedJson = JsonConvert.SerializeObject(list, Formatting.Indented);
Using Json.Net
//load from file
var initialJson = "[{\"id\":\"123\",\"name\":\"carl\"}]";
var array = JArray.Parse(initialJson);
var itemToAdd = new JObject();
itemToAdd["id"] = 1234;
itemToAdd["name"] = "carl2";
array.Add(itemToAdd);
var jsonToOutput = JsonConvert.SerializeObject(array, Formatting.Indented);
//save to file here
Using this method doesn't require strongly typed objects
You could replace this bit:
//load from file
var initialJson = "[{\"id\":\"123\",\"name\":\"carl\"}]";
With
var initialJson = File.ReadAllText(#"c:\myjson.json")
To load the json from a text file
A better performing solution than serializing/deserializing what may be a large file would be to open a FileStream, seek 1 character before the end, then serialize and write your new object into the array, then write a closing bracket. See this question C# How to delete last 2 characters from text file and write into the same line at the end my text?, I'll copy the code here - you already know how to serialize your object and encode it into bytes.
using(var fs = new FileStream("file.json")) {
fs.Seek(-1,SeekOrigin.End);
fs.Write(mySerializedJSONObjAsBytes,0,mySerializedJSONObjAsBytes.Length); // include a leading comma character if required
fs.Write(squareBracketByte, 0, 1);
fs.SetLength(fs.Position); //Only needed if new content may be smaller than old
}
Sorry haven't tested any of that, it's off the top of my head. Pro-tip: wrap FileStream in a StreamWriter so can write strings directly.
You could create a method:
public string AddObjectsToJson<T>(string json, List<T> objects)
{
List<T> list = JsonConvert.DeserializeObject<List<T>>(json);
list.AddRange(objects);
return JsonConvert.SerializeObject(list);
}
Then use it like this:
string baseJson = "[{\"id\":\"123\",\"name\":\"carl\"}]";
List<Person> personsToAdd = new List<Person>() { new Person(1234,"carl2") };
string updatedJson = AddObjectsToJson(baseJson, personsToAdd);
this would be a sample for you:
var list = JsonConvert.DeserializeObject<List<Example>>(json);
Example example = new Example();
example.name = "Product2";
example.id="1";
list.Add(example);
string output = JsonConvert.SerializeObject(list);
public class Example
{
public string id {get;set;}
public string name { get; set; }
}
I have been looking for a solution to this exact question for a week now. I finally figured out how to append it to the existing json array and not add it as a solo object after the array. Make sure you are using WriteAllText and not AppendAllText. Here is what I did:
JArray array = JsonConvert.DeserializeObject<JArray (jsonFile);
JObject obj = new JObject();
obj.Add("ID", "123");
obj.Add("Name", "Brian");
array.Add(obj);
var jsonToOutput = JsonConvert.SerializeObject(array, Formatting.Indented);
File.WriteAllText("fileName.json", jsonToOutput);
i am trying to deserialize a JSON-Object which looks quite similiar to an Array.
Here's the JSON-String:
...,"Test":[[0,1,2,3,4],[5,6,7,8,9],[10,11,12,13,14]],...
I do not want to deserialize it as 2D Array, because each of these values have an explicit meaning to me. I would like to access it like this:
Test[0].Example (0)
Test[0].Êxample2 (1)
Test[0].Example3 (2)
...
Test[2].Example (10)
I hope you got the idea and have a solution to my Problem.
I am using the Newtonsoft JSON Library together with C#.
EDIT1:
Maybe i should be more specific of how deserilisation is done until now:
JSON:"Object":{"A":0,"Test":[[0,1,2,3,4],[5,6,7,8,9],[10,11,12,13,14]],"B":1,...}
C#:
m_Object = JsonConvert.DeserializeObject<Object>(jsonString);
The Class Object is defined in C# containing all the fields of the JSON-String.
Object-Class:
class Object
{
public Int32 A {get;set;}
public Object Test {get;set;}
public Int32 B {get;set;}
}
You can use LINQ to JSON:
string json = "[[0,1,2,3,4],[5,6,7,8,9],[10,11,12,13,14]]";
var tests = JsonConvert.DeserializeObject<JArray>(json)
.Cast<JArray>()
.Select(a => new Test {
Example = (int)a[0],
Example2 = (int)a[1]
// etc
});
Result:
UPDATE: For your updated question - you can deserialize json object, and then access its properties by their keys
string json = #"{'A':0,'Test':[[0,1,2,3,4],[5,6,7,8,9],[10,11,12,13,14]],'B':1}";
var obj = JsonConvert.DeserializeObject<JObject>(json);
var test = (JArray)obj["Test"];
var result = new {
A = (int)obj["A"],
B = (int)obj["B"],
Test = test.Cast<JArray>().Select(a => new Test {
Example = (int)a[0],
Example2 = (int)a[1],
Example3 = (int)a[2],
Example4 = (int)a[3],
Example5 = (int)a[4]
})
};
I have this code:
[RdfSerializable( HasResourceUri=false )]
public class Item
{
[RdfProperty(true)]
public string MyProp;
}
[RdfSerializable]
public class AllItems
{
[RdfProperty(true)] public string mTitle;
private int id = new Random().Next(0, 20);
[ResourceUri]
public string ResourceUri
{
get { return "This " + id.ToString(); }
}
[RdfProperty(false, Name="item")]
public Item[] Items;
}
Created this way:
var item = new AllItems();
item.mTitle = "Hello World!";
item.Items = new Item[] { new Item() { MyProp = "test1" }, new Item() { MyProp = "test2" } };
var doc = Rdfizer.Serialize(item);
System.Console.Out.Write(doc.ToString());
Here is a part of the result:
<ns:AllItems rdf:about="This 1">
<ns:mTitle rdf:datatype="http://www.w3.org/2001/XMLSchema#string
">Hello World!</ns:mTitle>
<ns:item>
<ns:Item>
<ns:MyProp rdf:datatype="http://www.w3.org/2001/
XMLSchema#string">test1</ns:MyProp>
</ns:Item>
</ns:item>
<ns:item>
<ns:Item>
<ns:MyProp rdf:datatype="http://www.w3.org/2001/
XMLSchema#string">test2</ns:MyProp>
</ns:Item>
</ns:item>
</ns:AllItems>
First question is: How could I make and be a single tag?
Second question: How could I make tag not visible, but only its content? i.e. all of its children to be direct children of tag.
In short: what you want violates RDF specs. It looks like you would like to treat the output as XML, but you shouldn't!
In RDF, you manipulate the triples and you should never ever care how it is serialized into XML, because RDF is syntax independent and RDF/XML serialization specs allows to represent the same set of triples many different way. To illustrate it, you might pick RDF Tool "A" create an RDF document. You pick RDF Tool "B", load that document and save it under a new name again without any modification. You compare the two files and you will find the same triples inside but the two XML files might look quite different! You cannot make tags come and go, actually tags are "not your business" :).
The bottomline is, if you want to dictate how your output XML should look like, you should just forget RDF completely and just use plain old XML tools to do get the job done.