I would like to know how can I read a XML file from my desktop and put it into a string?
Here is my XML:
<smallusers>
<user id="1">
<name>John</name>
<motto>I am john, who are you?</motto>
</user>
<user id="2">
<name>Peter</name>
<motto>Hello everyone!</motto>
</user>
</smallusers>
<bigusers>
<user id="3">
<name>Barry</name>
<motto>Earth is awesome</motto>
</user>
</bigusers>
I want to store each user, but still detect if their small or big, is there a way to do this?
Before you downrate this, you might want to check google because I did research, but found nothing.
"Before you downrate this, you might want to check google because I
did research, but found nothing"
You found nothing because you don't know what you are searching for, also your XML is invalid, you need to enclose it in a rootElement. Then the first thing you need to do is read this file from the desktop if it exists.
You can check the size if you wish at that time and determine if this is "too large" even though it doesn't really matter. I highly doubt your XML file will be 5+ GB in size. If it is then you need an alternative, no single object in a .Net program may be over 2GB, the best you could do is 1,073,741,823 on a 64bit machine.
For very large XML files, anything above 1.0 GB, combine XmlReader and LINQ as stated by Jon Skeet here:
If your document is particularly huge, you can combine XmlReader and
LINQ to XML by creating an XElement from an XmlReader for each of your
"outer" elements in a streaming manner: this lets you do most of the
conversion work in LINQ to XML, but still only need a small portion of
the document in memory at any one time.
For small XML files, anything 1.0 GB or lower stick to the DOM as shown below.
With that said, what you need is to learn what Serialization and Deserialization mean.
Serialize convert an object instance to an XML document.
Deserialize convert an XML document into an object instance.
Instead of XML you can also use JSON, binary, etc.
In your case this is what can be done to Deserialize this XML document back into an Object in order for you to use in your code.
First fix up the XML and give it a Root.
<?xml version="1.0" encoding="UTF-8"?>
<DataRoot>
<smallusers>
<user id="1">
<name>John</name>
<motto>I am john, who are you?</motto>
</user>
<user id="2">
<name>Peter</name>
<motto>Hello everyone!</motto>
</user>
</smallusers>
<bigusers>
<user id="3">
<name>Barry</name>
<motto>Earth is awesome</motto>
</user>
</bigusers>
</DataRoot>
Then create the root class in C#, you may generate this directly in Visual Studio 2012+ by copying your XML and going to Edit - Paste Special, but I like to use: XML to C# Class Generator
Here is what your code would look like after you generate the C# Root Class for your XML, hope it helps you understand it better.
using System;
using System.Collections.Generic;
using System.IO;
using System.Xml;
using System.Xml.Serialization;
namespace ConsoleApplication1
{
public class Program
{
[XmlRoot(ElementName = "user")]
public class User
{
[XmlElement(ElementName = "name")]
public string Name { get; set; }
[XmlElement(ElementName = "motto")]
public string Motto { get; set; }
[XmlAttribute(AttributeName = "id")]
public string Id { get; set; }
}
[XmlRoot(ElementName = "smallusers")]
public class Smallusers
{
[XmlElement(ElementName = "user")]
public List<User> User { get; set; }
}
[XmlRoot(ElementName = "bigusers")]
public class Bigusers
{
[XmlElement(ElementName = "user")]
public User User { get; set; }
}
[XmlRoot(ElementName = "DataRoot")]
public class DataRoot
{
[XmlElement(ElementName = "smallusers")]
public Smallusers Smallusers { get; set; }
[XmlElement(ElementName = "bigusers")]
public Bigusers Bigusers { get; set; }
}
static void Main(string[] args)
{
string testXMLData = #"<DataRoot><smallusers><user id=""1""><name>John</name><motto>I am john, who are you?</motto></user><user id=""2""><name>Peter</name><motto>Hello everyone!</motto></user></smallusers><bigusers><user id=""3""><name>Barry</name><motto>Earth is awesome</motto></user></bigusers></DataRoot>";
var fileXmlData = File.ReadAllText(#"C:\XMLFile.xml");
var deserializedObject = DeserializeFromXML(fileXmlData);
var serializedToXML = SerializeToXml(deserializedObject);
//I want to store each user, but still detect if their small or big, is there a way to do this?
foreach (var smallUser in deserializedObject.Smallusers.User)
{
//Iterating your collection of Small users?
//Do what you need here with `smalluser`.
var name = smallUser.Name; //Example...
}
Console.WriteLine(serializedToXML);
Console.ReadKey();
}
public static string SerializeToXml(DataRoot DataObject)
{
var xsSubmit = new XmlSerializer(typeof(DataRoot));
using (var sw = new StringWriter())
{
using (var writer = XmlWriter.Create(sw))
{
xsSubmit.Serialize(writer, DataObject);
var data = sw.ToString();
writer.Flush();
writer.Close();
sw.Flush();
sw.Close();
return data;
}
}
}
public static DataRoot DeserializeFromXML(string xml)
{
var xsExpirations = new XmlSerializer(typeof(DataRoot));
DataRoot rootDataObj = null;
using (TextReader reader = new StringReader(xml))
{
rootDataObj = (DataRoot)xsExpirations.Deserialize(reader);
reader.Close();
}
return rootDataObj;
}
}
}
Related
Trying to deserialize a XML log file. And cannot seem to get anything but Error in XML Document(0,0). I am guessing it has something to do with my class but I cannot seem to find a solution. I cannot change the XML formatting as this is a log file coming from a server (just simplified)
XML
<?xml version="1.0" encoding="utf-8"?>
<POSLog>
<Transaction>
<RetailStoreID>1</RetailStoreID>
<SequenceNumber>2</SequenceNumber>
</Transaction>
<Transaction>
<RetailStoreID>1</RetailStoreID>
<SequenceNumber>3</SequenceNumber>
</Transaction>
</POSLog>
Class
[Serializable()]
public class Transaction
{
[XmlElement("RetailStoreID")]
public string RetailStoreID { get; set; }
[XmlElement("SequenceNumber")]
public string SequenceNumber { get; set; }
}
[Serializable()]
[XmlRoot("POSLog")]
public class POSLog
{
[XmlArray("POSLog")]
[XmlArrayItem("Transaction", typeof(Transaction))]
public Transaction[] Transaction { get; set; }
}
Deserialize code
POSLog poslog = new POSLog();
string path = "POSLog.xml";
XmlSerializer serializer = new XmlSerializer(typeof(POSLog));
StreamReader reader = new StreamReader(path);
poslog = (POSLog)serializer.Deserialize(reader);
Found fix by switching from StreamReader to FileStream along with changes to the class. Changing encoding didn't seem to help when using the StreamReader.
I cannot reproduce the problem you are seeing. However, there is an issue with the POSLog class -- it needs to be defined as follows:
[Serializable()]
[XmlRoot("POSLog")]
public class POSLog
{
[XmlElement("Transaction")]
public Transaction[] Transaction { get; set; }
}
Your XML has a root element <POSLog> containing a repeating sequence of <Transaction> elements. [XmlElement("Transaction")] maps the array to just such a one-level repeating sequence.
Example fiddle.
Changing the Class to the follow above answer
[Serializable()]
[XmlRoot("POSLog")]
public class POSLog
{
[XmlElement("Transaction")]
public Transaction[] Transaction { get; set; }
}
Along with Changing the following StreamReader lines
StreamReader reader = new StreamReader(path);
poslog = (POSLog)serializer.Deserialize(reader);
To this:
FileStream fs = new FileStream(path, FileMode.Open);
poslog = (POSLog)serializer.Deserialize(fs);
Fixed the issue I was having with the root element and I was able to deserialize the XML. Thanks to dbc for help in getting me started solving a solution for the first time in a forum!
I am new to unit testing and I am wondering what would be the best practices for unit testing xml deserialisation.
Consider the following xml:
<people>
<person id="1">
<name>Joe</name>
<age>28</age>
</person>
<person id="2">
<name>Jack</name>
<age>38</age>
</person>
</people>
And the following model class for the people:
[XmlRoot(ElementName ="people")]
public class People
{
public People() { PeopleList = new List<Person>(); }
[XmlElement("person")]
public List<Person> PeopleList { get; set; }
}
public class Person
{
[XmlAttribute("id")]
public int id { get; set; }
[XmlElement("name")]
public string Name { get; set; }
[XmlElement("age")]
public int Age { get; set; }
}
I deserialize the xml using:
public List<Person> GetListOfPeople()
{
People plist = new People();
string content;
using (StreamReader sr = new StreamReader(manager.Open("People.xml")))
{
var serializer = new XmlSerializer(typeof(People));
plist = (People)serializer.Deserialize(sr);
}
return plist.PeopleList;
}
What would be the best methods to unit test the GetListOfPeople method above?
If you can change your method to take an xml file as an input parameter, you can have a sample xml file created and added to your test project. Since you know the values of your xml file, you can start comparing the values directly.
Considering you'll use the sample file you provided in your test, you can verify like this:
var persons = x.GetListOfPeople("sample.xml");
Assert.AreEqual("Joe", persons[0].Name);
Assert.AreEqual(38, persons[1].Age);
If the xml file is coming to your code from some source and you think it couldn't be following your xml schema all the time, then probably you can create some sample xml files again which violate your schema and prepare tests to call your method which should throw some exception if schema is not correct.
Hope this helps.
I have XML file like this:
<?xml version="1.0"?>
<catalog>
<book id="1" date="2012-02-01">
<title>XML Developer's Guide</title>
<price>44.95</price>
<description>
An in-depth look at creating applications
with XML.
</description>
</book>
<book id="2" date="2013-10-16">
<author>Mark Colsberg</author>
<title>Dolor sit amet</title>
<price>5.95</price>
<description>Lorem ipsum</description>
</book>
</catalog>
How to quick convert it to C# classes to use access data by LINQ?
Do I have to write the class manually for any XML file case?
What about JSON format?
Is the XSD the only solution?
You have two possibilities.
Method 1. XSD tool
Suppose that you have your XML file in this location C:\path\to\xml\file.xml
Open Developer Command Prompt
You can find it in Start Menu > Programs > Microsoft Visual Studio 2012 > Visual Studio Tools
Or if you have Windows 8 can just start typing Developer Command Prompt in Start screen
Change location to your XML file directory by typing cd /D "C:\path\to\xml"
Create XSD file from your xml file by typing xsd file.xml
Create C# classes by typing xsd /c file.xsd
And that's it! You have generated C# classes from xml file in C:\path\to\xml\file.cs
Method 2 - Paste special
Required Visual Studio 2012+
Copy content of your XML file to clipboard
Add to your solution new, empty class file (Shift+Alt+C)
Open that file and in menu click Edit > Paste special > Paste XML As Classes
And that's it!
Usage
Usage is very simple with this helper class:
using System;
using System.IO;
using System.Web.Script.Serialization; // Add reference: System.Web.Extensions
using System.Xml;
using System.Xml.Serialization;
namespace Helpers
{
internal static class ParseHelpers
{
private static JavaScriptSerializer json;
private static JavaScriptSerializer JSON { get { return json ?? (json = new JavaScriptSerializer()); } }
public static Stream ToStream(this string #this)
{
var stream = new MemoryStream();
var writer = new StreamWriter(stream);
writer.Write(#this);
writer.Flush();
stream.Position = 0;
return stream;
}
public static T ParseXML<T>(this string #this) where T : class
{
var reader = XmlReader.Create(#this.Trim().ToStream(), new XmlReaderSettings() { ConformanceLevel = ConformanceLevel.Document });
return new XmlSerializer(typeof(T)).Deserialize(reader) as T;
}
public static T ParseJSON<T>(this string #this) where T : class
{
return JSON.Deserialize<T>(#this.Trim());
}
}
}
All you have to do now, is:
public class JSONRoot
{
public catalog catalog { get; set; }
}
// ...
string xml = File.ReadAllText(#"C:\path\to\xml\file.xml");
var catalog1 = xml.ParseXML<catalog>();
string json = File.ReadAllText(#"C:\path\to\json\file.json");
var catalog2 = json.ParseJSON<JSONRoot>();
Here you have some Online XML <--> JSON Converters: Click
You can follow this simple step
1.Please Add using System.Xml as a reference;
2.Make a class named book in this way
public class book
{
public Nullable<System.DateTime> date{ get; set; }
public decimal price { get; set; }
public string title { get; set; }
public string description { get; set; }
}
try
{
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load("Write down full path");
XmlNodeList dataNodes = xmlDoc.SelectNodes("/catalog");
foreach (XmlNode node in dataNodes)
{
book objbook = new book();
objbook.date=Convert.ToDateTime(node.Attributes["date"].Value);
objbook.title=node.SelectSingleNode("title").InnerText;
objbook.description=node.SelectSingleNode("description").InnerText;
objbook.price=Convert.ToDecimal(node.SelectSingleNode("price").InnerText);
}
}
catch(Exception ex)
{
throw ex;
}
Use the XML Schema Definition Tool xsd.exe found in your framework tools to convert your schema into a serializable class or dataset.
xsd file.xsd {/classes | /dataset} [/element:element]
[/language:language] [/namespace:namespace]
[/outputdir:directory] [URI:uri]
And in example, whereas the C# class will be generated in the same directory as the xsd tool:
xsd /c YourFile.xsd
Use the super simple way using 'Paste XML As Classes' functionality in Visual studio menu.
1.copy the xml source in the clipboard, something like CTRL+A and CTRL+C
2.Go to 'Edit' Menu -> Paste Special -> Paste XML As Classes, to paste the generated classes based on the source xml"
Ref: More steps in detail at this link
Here is one another easy way to parse xml file using Cinchoo ETL, an open source library
Define POCO class as below
public class Book
{
[ChoXPath("#id")]
public int Id { get; set; }
[ChoXPath("#date")]
public DateTime Date { get; set; }
[ChoXPath("author")]
public string Author { get; set; }
[ChoXPath("title")]
public string Title { get; set; }
[ChoXPath("price")]
public double Price { get; set; }
[ChoXPath("description")]
public string Description { get; set; }
}
Use it to the parser as below
using (var r = new ChoXmlReader<Book>("*** Xml file path ***")
.WithXPath("//catalog/book", true)
)
{
foreach (var rec in r)
rec.Print();
}
Sample fiddle: https://dotnetfiddle.net/3UI82F
How I read in the specific value of an XML attribute from a node when my XML looks like the following:
<Settings>
<Display_Settings>
<Screen>
<Name Name="gadg" />
<ScreenTag Tag="asfa" />
<LocalPosition X="12" Y="12" Z="12" />
</Screen>
</Display_Settings>
</Settings>
I only know how to read in the inner text value of XML and not the attribute value. For instance, I want the value of X in LocalPosition. This is what I've tried so far;
XmlNodeList nodeList = xmlDoc.GetElementsByTagName("Screen");
foreach (XmlNode nodeInfo in nodeList)
{
XmlNodeList nodeContent = nodeInfo.ChildNodes;
foreach (XmlNode nodeItems in nodeContent)
{
if (nodeItems.Name == "Tag")
{
print("There is a name");
}
if (nodeItems.Name == "LocalPosition")
{
print("TEST");
}
}
}
Though for what I want to do, I think this is the wrong way to go about it. Can someone point in the right direction please?
You can use LINQ to XML:
var xdoc = XDocument.Load(path_to_xml);
int x = (int)xdoc.Descendants("LocalPosition").First().Attribute("X");
Or with XPath
int x = (int)xdoc.XPathSelectElement("//LocalPosition").Attribute("X");
string XValue= nodeItems.Attributes["X"].Value; // will solve your problem.
I was a little confused when I first started parsing XML with C# too! Instead of trying to write it all yourself .NET provides System.XML.Linq and System.XML.Serialization to help us with all of the hard stuff!
This approach is slightly different as we:
Load the XML document into a System.XML.Linq.XDocument,
Deserialize the XDocument into .NET objects that we can use as we please =]
I hope you don't mind, but I tweaked your XML example a little bit. Try to avoid using too many attributes within your elements, as they tend to reduce readability. The first line of the XML sample just highlights the version that is being used.
You should be able to copy and paste the code sample below into a new console application to get a feel for how it works. Just make sure your XML file is in the ..\bin\Debug folder (otherwise you will need to provide a full file path reference to it).
As you can see, in this example your XML elements (Display_Settings, Screen, Name, ScreenTag, and LocalPosition) are all classes that we decorate with XMLElement attributes. These classes just have public properties that are automatically populated when we call Deserialize(). Neat!
The same applies to the X, Y and Z attributes.
There are a bunch of tutorials that can explain this a lot better than me - enjoy! =]
XML Example
<?xml version="1.0"?>
<Settings>
<Display_Settings>
<Screen>
<Name>NameGoesHere</Name>
<ScreenTag>ScreenTagGoesHere</ScreenTag>
<LocalPosition X="12" Y="12" Z="12" />
</Screen>
</Display_Settings>
</Settings>
Complete Code Sample
using System;
using System.Xml.Linq;
using System.Xml.Serialization;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
// Create XDocument to represent our XML file
XDocument xdoc = XDocument.Load("XmlFile.xml");
// Create a deserializer and break down our XML into c# objects
XmlSerializer deserializer = new XmlSerializer(typeof(Settings));
// Deserialize into a Settings object
Settings settings = (Settings)deserializer.Deserialize(xdoc.CreateReader());
// Check that we have some display settings
if (null != settings.DisplaySettings)
{
Screen screen = settings.DisplaySettings.Screen;
LocalPosition localPosition = screen.LocalPosition;
// Check to make sure we have a screen tag before using it
if (null != screen.ScreenTag)
{
Console.WriteLine("There is a name: " + screen.ScreenTag);
}
// We can just write our integers to the console, as we will get a document error when we
// try to parse the document if they are not provided!
Console.WriteLine("Position: " + localPosition.X + ", " + localPosition.Y + ", " + localPosition.Z);
}
Console.ReadLine();
}
}
[XmlRoot("Settings")]
public class Settings
{
[XmlElement("Display_Settings")]
public DisplaySettings DisplaySettings { get; set; }
}
public class DisplaySettings
{
[XmlElement("Screen")]
public Screen Screen { get; set; }
}
public class Screen
{
[XmlElement("Name")]
public string Name { get; set; }
[XmlElement("ScreenTag")]
public string ScreenTag { get; set; }
[XmlElement("LocalPosition")]
public LocalPosition LocalPosition { get; set; }
}
public class LocalPosition
{
[XmlAttribute("X")]
public int X { get; set; }
[XmlAttribute("Y")]
public int Y { get; set; }
[XmlAttribute("Z")]
public int Z { get; set; }
}
}
Try with nodeItems.Attributes["X"].Value
I am trying to figure out how to do XML serialization.
This is how I want my XML document too look like in the end
<course>
<name></name>
<backgroundColor></backgroundColor>
<fontColor></fontColor>
<sharingKey></sharingKey>
<task id="">
<taskName></taskName>
<description></description>
</task>
<task id="">
<taskName></taskName>
<description></description>
</task>
</course>
So far mine looks like
<?xml version="1.0" encoding="utf-8"?>
<Course xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<name>name</name>
<backgroundColor>test</backgroundColor>
<fontColor>test2</fontColor>
<sharingKey>9324bfab-6cc7-49e5-84f7-56130b8dc099</sharingKey>
<task id="first Task" />
<task id="Second task" />
</Course>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Serialization;
namespace ConsoleApplication1
{
[XmlRoot("Course")]
public class MyWrapper
{
public MyWrapper()
{
TaskList = new List<Tasks>();
}
[XmlElement("name")]
public string Name { get; set; }
[XmlElement("backgroundColor")]
public string BackgroundColor { get; set; }
[XmlElement("fontColor")]
public string FontColor { get; set; }
[XmlElement("sharingKey")]
public Guid SharingKey { get; set; }
[XmlElement("task")]
public List<Tasks> TaskList { get; set; }
}
public class Tasks
{
[XmlAttribute("id")]
public string Id { get; set; }
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Serialization;
using System.IO;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Tasks task = new Tasks();
task.Id = "first Task";
Tasks task2 = new Tasks();
task2.Id = "Second task";
MyWrapper wrap = new MyWrapper();
wrap.BackgroundColor = "test";
wrap.FontColor = "test2";
wrap.Name = "name";
wrap.SharingKey = Guid.NewGuid();
wrap.TaskList.Add(task);
wrap.TaskList.Add(task2);
SerializeToXML(wrap);
}
static public void SerializeToXML(MyWrapper list)
{
XmlSerializer serializer = new XmlSerializer(typeof(MyWrapper));
TextWriter textWriter = new StreamWriter(#"C:\New folder\test.xml");
serializer.Serialize(textWriter, list);
textWriter.Close();
}
}
}
So my question is with the "id" for the task.
All I have is another class with this in it
[XmlAttribute("id")]
public string Id { get; set; }
How did it know to put this attribute in the task tag?
What happens if I wanted to have another property
[XmlElement()]
public string TaskName {get; set;}
Say I wanted to have an attribute with this element how would I make sure that the attribute would be with TaskName not with Task?
[XmlElement("task")]
public List<Tasks> TaskList { get; set; }
This part of your code told it to serialize every Tasks object in an element called "task". The serializer looks at the properties on the Tasks class and finds the Id property which you marked with [XmlAttribute("id")] so it gets serialized as an attribute to the "task" element for the object.
I'm not sure I understand your second question. You cannot add an attribute to the element because its type is a string. Instead you would have to create a new class to wrap the concept of a task name which would have a name property and whatever other properties you wanted to add to it.
Basically: XML elements can have two kinds of properties, attributes and elements. You defined an XML element task and an attribute on task called id, thus the serializer adds the attribute to task.
Now, suppose you want to add elements to reside within task -- this is also okay, as I said, XML elements can contain other elements, or have attributes. Simply define any elements you want to contain within task...within task.
If you want to have an attribute attached to a different element, you need to create a new XML element (here that corresponds to a class) and literally set it as an attribute type using the [XmlAttribute("id")] syntax.
Perhaps there's a disconnect for you here -- when you define the simplest form of element, we can call that a simpleType, and it can have values that are Strings or Integers or any kind of relatively primitive type (dates are valid, too). But if you want that same element to also have attributes, it suddenly needs to become a complexType, since it has complexContent -- it may contains both simple content, and properties, like, say, an attribute.
Take a look at how to write XML Schemas - w3schools have some excellent tutorials - I think that you'll gain a much better understanding of this whole mix of simple and complex content. Effectively, by defining an XML serialization for your classes you are also defining an XML schema; and you can in fact compile your code into such a schema. Understanding to construct the schemas will let you understand how to construct your code to generate the appropriate schemas, and additionally, understand your serialization output.