I have the following class definition in C#:
class Supervisor
{
public string Id { set; get; }
public string Name { set; get; }
public int Contracts { set; get; }
public long Volume { set; get; }
public int Average { get; }
}
I also have this xml document :
<digital-sales xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<supervisor id="1236674">
<Name>Hiroki</Name>
<Contract>11</Contract>
<Volume>1036253</Volume>
<Average>94205</Average>
</supervisor>
<supervisor id="123459">
<Name>Ayumi</Name>
<Contract>5</Contract>
<Volume>626038</Volume>
<Average>125208</Average>
</supervisor> ...
</digital-sales>
Inside the main I create object for each supervisor and fill its data by searching id.
However I always get null as result. This is my Main method:
static void Main(string[] args)
{
// load the document
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(#"C:\Users\Hideki\ShinDeta.xml");
Supervisor ayumi = new Supervisor();
// this line return null
XmlNode ayumiNode = xmlDoc.GetElementById("1236674");
// ayumi.Id = (supply expression here);
// ayumi.Name = (supply expression here);
// ayumi.Contracts = (supply expression here);
// ayumi.Volume = (supply expression here);
// ayumi.Average = (supply expression here);
}
Can someone points me to the shortest way to achieve this?. No linq syntax please I am not familiar with it at all.
You could use Xml serialization to accomplish this. Here's an example
[XmlType("supervisor")]
public class Supervisor
{
[XmlAttribute("id")]
public string Id { set; get; }
public string Name { set; get; }
[XmlElement("Contract")]
public int Contracts { set; get; }
public long Volume { set; get; }
public int Average { set; get; }
}
static void Main(string[] args)
{
try
{
XmlSerializer xs = new XmlSerializer(typeof(List<Supervisor>), new XmlRootAttribute("digital-sales"));
using (FileStream fileStream = new FileStream(#"C:\temp\ShinDeta.xml", FileMode.Open, FileAccess.Read, FileShare.Read))
{
var supervisors = xs.Deserialize(fileStream) as List<Supervisor>;
foreach (Supervisor supervisor in supervisors)
{
Debug.WriteLine($"Id: {supervisor.Id}, Name: {supervisor.Name}");
}
}
}
catch(Exception e)
{
Debug.WriteLine(e.Message);
}
}
This outputs:
Id: 1236674, Name: Hiroki
Id: 123459, Name: Ayumi
Related
I have an XML file that I am parsing through and have come across a specific element that has it's own child nodes. The XML file is below:
<status.AppleSettings>
<AppleInstance MaxCost="250" Status="77" NewMode="5" SharePrice="350"
FlagTF="False" TimeClock="0" TimeClockSec="14"
Options="7532890" ID="JK_7755" Owner="SLP90"
Server="PA.SL90.COL" Name="SLP90" GroupName="COL.PA"
Instance="AppleServiceInstance" NewFlag="True" FinalCount="0"/>
<AppleInstance MaxCost="5" Status="0" NewMode="1" SharePrice="0"
FlagTF="False" TimeClock="300" TimeClockSec="1000"
Options="56794577431" Owner="A.CON" Instance="SL91"
NewFlag="True" FinalCount="1" List="1450, 1430"
Keyrepo="SYSTEMSERVER_7671902"/>
</status.AppleSettings>
As you can see, there's a parent node - AppleSettings and then two child nodes w/ the same name - AppleInstance. I created two separate classes for the child nodes since they have different attributes. I am able to access AppleSettings and when I do a quickwatch I can see the two child nodes inside, I just can't figure out how to access them. New to XML parsing and C# so everything is trial and error, learning a lot from stackoverflow.
Here is the code I have to access the AppleSettings parent node:
private List<Data> GetAppleSettingsNode(List<XmlDocument> XMLdocument, List<Data> DataList)
{
for (int i = 0; i < XMLdocument.Count(); i++)
{
AppleSettings temp = new AppleSettings();
var temp2 = XMLdocument[i].DocumentElement.SelectNodes("//AppleSettings");
foreach (var node in temp2)
{
var temp3 = node.ToString();
}
XmlNode xmlNode1 = XMLdocument[i].SelectSingleNode("//AppleSettings");
XmlSerializer serial1 = new XmlSerializer(typeof(AppleSettings));
temp = (AppleSettings)serial1.Deserialize(new XmlNodeReader(xmlNode1));
}
}
Is it even necessry to access the AppleSettings node? Could I go directly to the two AppleInstance child nodes? If someone could help me out, I'd appreciate it. Thanks!
It is better to use LINQ to XML API.
(1) The code below shows how to access any XML attribute by its name.
(2) .FirstOrDefault()?.Value technique will prevent exceptions generation when an attribute is missing.
c#
void Main()
{
const string FILENAME = #"e:\Temp\AppleSettings.xml";
XDocument doc = XDocument.Load(FILENAME);
foreach (var el in doc.Descendants("AppleInstance"))
{
Console.WriteLine("MaxCost={0}", el.Attributes("MaxCost").FirstOrDefault()?.Value);
Console.WriteLine("Instance={0}", el.Attributes("Instance").FirstOrDefault()?.Value);
Console.WriteLine("GroupName={0}", el.Attributes("GroupName").FirstOrDefault()?.Value);
}
}
Try following :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
namespace ConsoleApplication8
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
XmlReader reader = XmlReader.Create(FILENAME);
XmlSerializer serializer = new XmlSerializer(typeof(Root));
Root root = (Root)serializer.Deserialize(reader);
}
}
public class Root
{
[XmlArray("status.AppleSettings")]
[XmlArrayItem("AppleInstance")]
public List<ApppleInstance> AppleInstances { get; set; }
}
public class ApppleInstance
{
[XmlAttribute()]
public int MaxCost { get; set; }
[XmlAttribute()]
public int Status { get; set; }
[XmlAttribute()]
public int NewMode { get; set; }
[XmlAttribute()]
public int SharePrice { get; set; }
private Boolean _FlagTF { get; set; }
[XmlAttribute()]
public string FlagTF
{
get { return _FlagTF? "True" : "False";}
set { _FlagTF = (value == "True") ? true : false;}
}
[XmlAttribute()]
public int TimeClock { get; set; }
[XmlAttribute()]
public int TimeClockSec { get; set; }
[XmlAttribute()]
public long Options { get; set; }
[XmlAttribute()]
public string ID { get; set; }
[XmlAttribute()]
public string Owner { get; set; }
[XmlAttribute()]
public string Server { get; set; }
[XmlAttribute()]
public string Name { get; set; }
[XmlAttribute()]
public string GroupName { get; set; }
[XmlAttribute()]
public string Instance { get; set; }
private Boolean _NewFlag { get; set; }
[XmlAttribute()]
public string NewFlag
{
get { return _NewFlag ? "True" : "False"; }
set { _NewFlag = (value == "True") ? true : false; }
}
[XmlAttribute()]
public int FinalCount { get; set; }
private int[] _List { get; set; }
[XmlAttribute()]
public string List
{
get { return string.Join(",",_List);}
set { _List = value.Split(new char[] {','}).Select(x => int.Parse(x)).ToArray() ;}
}
[XmlAttribute()]
public string Keyrepo { get; set; }
}
}
The i of LargeXMLResponse[i] is loop count of the Large XML response if your response tag in wrapped up in between, and if you have a alternative way please go ahead with.
var ResponseToList = LargeXMLResponse[i].Descendants("Response").ToList();
if (ResponseToList.Count() > 0){
for (var pf = 0; pf < ResponseToList.Count(); pf++)
{
ResponseInfoList.Add(new ResponseToList{
id = ResponseToList[pf].Descendants("Block").Attributes("id").Count() > 0 ?
ResponseToList[pf].Descendants("Block ").Attributes("id").First().Value : "",
});
}
}
I wrote a generic method for Object to XML string using XMLSerializer class.
Below is my class
public class SampleJson
{
public string fname { get; set; }
public string lname { get; set; }
public int age { get; set; }
public AdditionalInformation AdditionalInformation { get; set; }
}
public class AdditionalInformation
{
public string firstlane { get; set; }
public string secondlane { get; set; }
public decimal? cityCode { get; set; }
public int? countryCode { get; set; }
public bool? isValid { get; set; }
public DateTime enteredDate { get; set; }
}
And below is Generic Method
public class QAZ
{
public static string Foo<T>(T dataToSerialize)
{
var stringWriter = new StringWriter();
XmlTextWriter xmlTextWriter = null;
var serializer = new XmlSerializer(dataToSerialize.GetType());
xmlTextWriter = new XmlTextWriter(stringWriter);
serializer.Serialize(xmlTextWriter, dataToSerialize);
return stringWriter.ToString();
}
}
class Bar
{
static void Main(string[] args)
{
var sampleJson = typeof(SampleJson);
var fooMethod = typeof(QAZ).GetMethod("Foo");
var fooOfBarMethod = fooMethod.MakeGenericMethod(new[] {sampleJson});
string xml= fooOfBarMethod.Invoke(new QAZ(), new object[] {new SampleJson()}).ToString();
Console.ReadKey();
}
}
But I'm getting the output is
<?xml version="1.0" encoding="UTF-16"?>
-<SampleJson xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<age>0</age>
</SampleJson>
I don't understand why XmlSerializer serializes only int property.
Can anyone please tell me the issue that I'm doing.
The main agenda here is I want to generate an xsd for SampleJson class. In order to do that I am trying to convert the class to xml. From xml to xsd. Is there a way to generate xsd from a class?
I think this might help you to understand better, I wrote an example please do like or dislike if it has or hasn't helped.
public class Vehicle
{
public string VRM;
}
class Program
{
static void Main(string[] args)
{
var Reg = new Vehicle { VRM = "LP65 UGT" };
var writer = new System.Xml.Serialization.XmlSerializer(typeof(Vehicle));
var wfile = new System.IO.StreamWriter(#"C:\Myexample\NewVehicle.xml");
writer.Serialize(wfile, Reg);
wfile.Close();
Console.WriteLine("Vehicle Reg is now written in xml format ");
Console.ReadKey();
}
}
The above example will write successfully to XML file ensure you create the folder first on your C drive My example and then run the above to see the result for yourself and see if it can point you to the correct direction hopefully.
So, I have XML like this:
<tileset firstgid="1" name="simple_tiles" tilewidth="32" tileheight="32" tilecount="16" columns="8">
<image source="../Users/mkkek/Pictures/rpg/default_tiles_x.png" width="256" height="64"/>
</tileset>
When I'm at the tileset node, how can I access the image node and its source attribute? My code is as follows:
public void LoadMaps(ContentManager content)
{
Dictionary<string, string> mapsToLoad = InitMapsToLoad();
foreach (KeyValuePair<string, string> mapToLoad in mapsToLoad)
{
Map map = new Map();
map.Name = Path.GetFileNameWithoutExtension(mapToLoad.Value);
reader = XmlReader.Create("Content/" + mapToLoad.Value);
while(reader.Read())
{
if(reader.NodeType == XmlNodeType.Element)
{
switch(reader.Name)
{
case "tileset":
if(!Tilesets.Any(ts => ts.Name == reader.GetAttribute("name")))
{
// handling the image node here
}
break;
}
}
}
}
}
I usually prefer to use LINQ to XML because I find it's API to be much easier to use than XmlReader, a comparison between the technologies here.
If all you need is getting source attribute value from image element this can be achieved easily:
var doc = XDocument.Load("something.xml");
var root = doc.DocumentElement;
var imageElements = root.Elements("image").ToList();
foreach (var imageElement in imageElements)
{
var sourceAttribute = imageElement.Attribute("source");
var sourceValue = sourceAttribute.Value;
//do something with the source value...
}
More about basic queries in LINQ to XML here.
I will suggest to create some classes that represents the Xml structure, something like this :
[XmlRoot(ElementName = "image")]
public class Image
{
[XmlAttribute(AttributeName = "source")]
public string Source { get; set; }
[XmlAttribute(AttributeName = "width")]
public string Width { get; set; }
[XmlAttribute(AttributeName = "height")]
public string Height { get; set; }
}
[XmlRoot(ElementName = "tileset")]
public class Tileset
{
[XmlElement(ElementName = "image")]
public Image Image { get; set; }
[XmlAttribute(AttributeName = "firstgid")]
public string Firstgid { get; set; }
[XmlAttribute(AttributeName = "name")]
public string Name { get; set; }
[XmlAttribute(AttributeName = "tilewidth")]
public string Tilewidth { get; set; }
[XmlAttribute(AttributeName = "tileheight")]
public string Tileheight { get; set; }
[XmlAttribute(AttributeName = "tilecount")]
public string Tilecount { get; set; }
[XmlAttribute(AttributeName = "columns")]
public string Columns { get; set; }
}
Then In some Utility class add the following method:
public static T DeserializeFromXml<T>(string xml)
{
if (string.IsNullOrEmpty(xml))
{
return default(T);
}
var serializer = new XmlSerializer(typeof(T));
T entity;
using (XmlReader reader = XmlReader.Create(new StringReader(xml)))
{
entity = (T)serializer.Deserialize(reader);
}
return entity;
}
Now you will be able to access to the Image object using the following code:
Tileset tileset=DeserializeFromXml<Tileset>(yourXmlContent);
// now you can access the image from the tileset instance 'tileset.Image.Source'
You are almost done. Add this to your code.
// handling the image node here
if (reader.ReadToDescendant("image"))
{
string source = reader.GetAttribute("source");
}
I have the follow XML structure:
<Document>
<Sectors>
<Sector>
SectorName1
<Subsectors>
<Subsector>Subsector1</Subsector>
<Subsector>Subsector2</Subsector>
</Subsectors>
</Sector>
<Sector>
SectorName2
<Subsectors>
<Subsector>Subsector1</Subsector>
<Subsector>Subsector2</Subsector>
</Subsectors>
</Sector>
</Sectors>
</Document>
Also I have classes for deserialize:
public class MetaDataXML
{
public class SectorXML
{
[XmlArrayItem(ElementName = "Sector")]
string SectorName { get; set; }
[XmlArray]
[XmlArrayItem(ElementName = "Subsector")]
public List<string> Subsectors { get; set; }
}
public List<SectorXML> Sectors { get; set; }
}
And part of code which do deserialize:
var xRoot = new XmlRootAttribute { ElementName = "Document", IsNullable = true };
var reader = new XmlSerializer(typeof(MetaDataXML), xRoot);
var data = (MetaDataXML)reader.Deserialize(streamXML);
After deserialization I successfully get subsectors velues, but I didn't get values for SectorName. How I need to organize my structure of class that I'll get values "SectorName1" and "SectorName2" for my string SectorName property?
I found that that this case it's a "Mixed Content". How we can parse this text values?
Whilst I am not entirely sure what it is you're trying to achieve here, I've made a few modifications to your XML class and provided some sample code below that is able to retrieve all of the information about a sector, including its name and the name of all the subsectors inside it.
XML Class:
namespace DocumentXml
{
[XmlRoot("Document")]
public class Document
{
[XmlArray("Sectors")]
[XmlArrayItem("Sector")]
public Sector[] Sectors { get; set; }
}
[XmlRoot("Sector")]
public class Sector
{
[XmlAttribute("SectorName")]
public string SectorName { get; set; }
[XmlArray("Subsectors")]
[XmlArrayItem("Subsector")]
public string[] Subsectors { get; set; }
}
}
Main Program Class:
namespace DocumentXml
{
class Program
{
static void Main(string[] args)
{
var path = #"D:\sandbox\DocumentXml\DocumentXml\Sample.xml";
var serializer = new XmlSerializer(typeof(Document));
var document = serializer.Deserialize(File.OpenRead(path)) as Document;
var sectors = document.Sectors;
foreach (var s in sectors)
{
Console.WriteLine($"Sector Name: {s.SectorName}");
foreach (var ss in s.Subsectors)
{
Console.WriteLine($"Subsector Name: {ss}");
}
Console.WriteLine();
}
Console.ReadKey();
}
}
}
Sample XML:
<Document>
<Sectors>
<Sector SectorName="SectorName1">
<Subsectors>
<Subsector>Subsector1</Subsector>
<Subsector>Subsector2</Subsector>
</Subsectors>
</Sector>
<Sector SectorName="SectorName2">
<Subsectors>
<Subsector>Subsector1</Subsector>
<Subsector>Subsector2</Subsector>
</Subsectors>
</Sector>
</Sectors>
</Document>
Output:
EDIT
Since the XML structure cannot be changed, this new class will preserve the structure and also allow you to get the value in question. XmlText returns everything inside the value so a custom set had to be used to ensure that the whitespace was correctly trimmed from it.
[XmlRoot("Document")]
public class MetaDataXml
{
[XmlArray("Sectors")]
[XmlArrayItem("Sector")]
public Sector[] Sectors { get; set; }
}
[XmlRoot("Sector")]
public class Sector
{
[XmlIgnore]
private string _sectorName;
[XmlText]
public string SectorName
{
get
{
return _sectorName;
}
set
{
_sectorName = value.Trim();
}
}
[XmlArray]
[XmlArrayItem(ElementName = "Subsector")]
public List<string> Subsectors { get; set; }
}
Sample Program:
class Program
{
static void Main(string[] args)
{
var path = #"D:\sandbox\DocumentXml\DocumentXml\Sample.xml";
using (var stream = File.OpenRead(path))
{
var deserializer = new XmlSerializer(typeof(MetaDataXml));
var data = (MetaDataXml)deserializer.Deserialize(stream);
foreach (var s in data.Sectors)
{
Console.WriteLine($"Sector Name: {s.SectorName}");
foreach (var ss in s.Subsectors)
{
Console.WriteLine($"Subsector Name: {ss}");
}
Console.WriteLine();
}
}
Console.ReadKey();
}
}
I have one xml file and I want to generate custom list from that xml using Linq.
here is my code. But I am not getting any records.Here is my code.
public class TemplateSettings {
public string DecimalSeparator { get; set; }
public string ThousandSeparator { get; set; }
public string DateSeparator { get; set; }
public string TimeSeparator { get; set; }
}
XML Here
<TemplateSetting>
<DecimalSeparator>1</DecimalSeparator>
<ThousandSeparator>2</ThousandSeparator>
<DateSeparator>3</DateSeparator>
<TimeSeparator>4</TimeSeparator>
<DateFormat>dd/MM/yyyy</DateFormat>
<ValueDelimiter>tr</ValueDelimiter>
<QuoteCharacter>r</QuoteCharacter>
<IsHeader>False</IsHeader>
</TemplateSetting>
And my code to get object from xml is
var a = (from x in objTemplateMasterEAL.TemplatSettingsXML.Elements("TemplateSetting")
select new TemplateSettings()
{
DateFormat = (string)x.Element("DateFormat"),
DecimalSeparator = (string)x.Element("DecimalSeparator"),
ThousandSeparator = (string)x.Element("ThousandSeparator"),
DateSeparator = (string)x.Element("DateSeparator"),
TimeSeparator = (string)x.Element("TimeSeparator"),
QuoteCharacter = (string)x.Element("QuoteCharacter"),
ValueDelimiter = (string)x.Element("ValueDelimiter"),
IsHeaderLine = (bool)x.Element("IsHeader")
}).ToList<TemplateSettings>();
Can any one suggest me what is wrong here ?
If your goal is just to deserialize the XML to object you can simply use this:
class Program
{
static void Main(string[] args)
{
using (StreamReader reader = new StreamReader("Sample.xml"))
{
var serializer = new XmlSerializer(typeof(TemplateSetting));
var templateSetting = (TemplateSetting)serializer.Deserialize(reader);
}
}
}
[XmlRoot]
public class TemplateSetting
{
public string DecimalSeparator { get; set; }
public string ThousandSeparator { get; set; }
public string DateSeparator { get; set; }
public string TimeSeparator { get; set; }
}
I make only on one change and its working fine for me.
<TemplateSettings>
<TemplateSetting>
<DecimalSeparator>1</DecimalSeparator>
<ThousandSeparator>2</ThousandSeparator>
<DateSeparator>3</DateSeparator>
<TimeSeparator>4</TimeSeparator>
<DateFormat>dd/MM/yyyy</DateFormat>
<ValueDelimiter>tr</ValueDelimiter>
<QuoteCharacter>r</QuoteCharacter>
<IsHeader>False</IsHeader>
</TemplateSetting>
</TemplateSettings>