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
Related
This is my current XML Response tag
<Response_Data_1234 diffgr:id="Response_Data_1234" msdata:rowOrder="0" diffgr:hasChanges="inserted">
<Status>File received.</Status>
<Time>2022-01-25T09:44:15.73+08:00</Time>
<Location>HKG</Location>
</Response_Data_1234>
the number 1234 in <Response_Data_1234> is a Response Data id, which will be dynamic depending on the request.
Could someone please me create a C# class in this scenario so that I can map the response directly to the class. Thanks in advance
Actually you should not have any unique identifier attached to XML element name. It should be added as attribute.
To answer your question:
There is no direct class attribute to ignore class name while deserialisation of xml string to object.
Option1 (better): Create mapper extension method for XNode to class attribute mapping and reuse it.
Option2:
If your xml string is small you can try to update name of root element and use it to deserialise.
sample code:
var responseDataXDoc = XDocument.Parse(xml);
responseDataXDoc.Root.Name = "ResponseData";
var serializer = new XmlSerializer(typeof(ResponseData));
var responseData = serializer.Deserialize(new StringReader(responseDataXDoc.ToString(SaveOptions.DisableFormatting)));
With Cinchoo ETL - an open source library, you can deserialize such xml easily as below
using (var r = ChoXmlReader<ResponseData>.LoadText(xml)
.WithXPath("//")
.WithXmlNamespace("diffgr", "")
.WithXmlNamespace("msdata", "")
)
{
var rec = r.FirstOrDefault();
rec.Print();
}
public class ResponseData
{
public string Status { get; set; }
public DateTime Time { get; set; }
public string Location { get; set; }
}
Sample fiddle: https://dotnetfiddle.net/HOOPOg
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;
}
}
}
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 wanna read this xml and convert it to list for inserting into database
please help
<?xml version="1.0" encoding="UTF-8"?>
-<xml>-<records>-<record><database path="J:\EndNote\PA-03\1.enl" name="1.enl">1.enl</database><source-app name="EndNote" version="14.0">EndNote</source-app><rec-number>38</rec-number>-<foreign-keys><key db-id="r50aeetv1taarsewtwsvrr2h2wtzde5z25pp" app="EN">38</key></foreign-keys><ref-type name="Journal Article">17</ref-type>-<contributors>-<authors>-<author><style size="100%" font="default" face="normal">Patrick Carpenter</style></author></authors></contributors>...
EDIT:
its for Exported EndNote
its so messy and it does not do the trick
please check this
full xml link
Quickest way to do this is to use xsd.exe to generate serialization classes :
1) generate schema definition
xsd file.xml [/outputdir:directory]
This step is not needed, if xml supplier has xsd schemas allready (sample xml does not have defined any used xsd schemas)
2) generate classes from xsd schema:
xsd file.xsd {/classes | /dataset} [/element:element]
[/language:language] [/namespace:namespace]
[/outputdir:directory] [URI:uri]
3) use xml serializer to deserialize from generated classes:
http://msdn.microsoft.com/en-us/library/dsh84875.aspx
Create classes for the model of the XML contents such as:
class Records
{
public List<Record> records { get; set }
}
class Record
{
public RecordDatabase database { get; set }
...
public int rec_number { get; set }
...
}
class RecordDatabase
{
public string path { get; set }
public string name { get; set }
}
...
Then you can deserialize your XML File into an object:
Records records = null;
string path = "importfile.xml";
XmlSerializer serializer = new XmlSerializer(typeof(Cars[]));
StreamReader reader = new StreamReader(path);
reader.ReadToEnd();
records = (records)serializer.Deserialize(reader);
reader.Close();
Just for some fun I was playing with the API of Last.fm. The XML file they return for top artists is structured like this:
<lfm status="ok">
<topartists user="xbonez" type="overall">
<artist rank="1">
<name>Evanescence</name>
<playcount>4618</playcount>
<mbid>f4a31f0a-51dd-4fa7-986d-3095c40c5ed9</mbid>
<url>http://www.last.fm/music/Evanescence</url>
<streamable>1</streamable>
<image size="small">http://userserve-ak.last.fm/serve/34/48488613.png</image>
<image size="medium">http://userserve-ak.last.fm/serve/64/48488613.png</image>
<image size="large">http://userserve-ak.last.fm/serve/126/48488613.png</image>
<image size="extralarge">http://userserve-ak.last.fm/serve/252/48488613.png</image>
<image size="mega">http://userserve-ak.last.fm/serve/500/48488613/Evanescence++PNG.png</image>
</artist>
</topartists>
</lfm>
This is how I'm deserealizing it.
I have a class called lfmStatus:
[Serializable()]
[XmlRootAttribute("lfm")]
public class lfmStatus
{
[XmlElement("artist")]
public List<Artists> TopArtists { get; set; }
}
And a Class Artists:
[Serializable()]
public class Artists
{
[XmlElement("name")]
public string Name { get; set; }
[XmlElement("playcount")]
public int playcount { get; set; }
[XmlElement("url")]
public string url { get; set; }
[XmlElement("streamable")]
public int streamable { get; set; }
[XmlElement("image")]
public string image { get; set; }
}
And then I deserealize using this code:
string XmlFile = "artists.xml";
XmlSerializer serializer = new XmlSerializer(typeof(lfmStatus));
lfmStatus LoadFile;
using (Stream reader = new FileStream(XmlFile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
try
{
Console.WriteLine("Beginning deserialization.");
// Call the Deserialize method to restore the object's state.
LoadFile = (lfmStatus)serializer.Deserialize(reader);
return LoadFile.TopArtists;
}
Now, this code works great for the XML if it did not have the topartists tag enveloping all the artists. But since it does, how do I change my code to handle that? I'm assuming I need to add another class.
You are missing the attribute(s) on a few types.
See XmlAttributeAttribute for more detail.
You are also missing the topartists element's type.
If I was you, I would get the XML schema and just use xsd.exe to generate the C# classes, and modify from there. It can also infer the schema based on XML if you really can't find it, this will give you a parsable result based on the input XML.
To see that you wrote correct code for deserializing the response XML you can use XSD. Open VS command prompt and give XSD LastFM.xml which generates and XSD file. Now give XSD LastFM.XSD which will generate a CS file. compare that one with the one you have written and check if you made any mistakes.