C# XML reading foreach always first value - c#

My XML
<?xml version="1.0" encoding="UTF-8"?>
<teklif>
<bilgiler>
<firma>Firma Adı</firma>
<aciklama>Açıklama</aciklama>
<isim>Ad Soyad</isim>
<telefon>Telefon</telefon>
<eposta>E Posta</eposta>
<urunler>
<urun>
<resimDosyasi>Dosya Seçilmedi</resimDosyasi>
<aciklama>Ürün Açıklaması</aciklama>
<birim>3,00</birim>
<miktar>1</miktar>
<toplam>0,00</toplam>
</urun>
<urun>
<resimDosyasi>Dosya Seçilmedi</resimDosyasi>
<aciklama>Ürün Açıklaması</aciklama>
<birim>5,00</birim>
<miktar>1</miktar>
<toplam>0,00</toplam>
</urun>
<urun>
<resimDosyasi>Dosya Seçilmedi</resimDosyasi>
<aciklama>aas</aciklama>
<birim>2,00</birim>
<miktar>1</miktar>
<toplam>0,00</toplam>
</urun>
</urunler>
And My Function which reads the XML file
XmlDocument doc = new XmlDocument();
doc.Load(filename);
XmlNodeList xmllist = doc.SelectNodes("/teklif/bilgiler/urunler");
foreach(XmlNode nod in xmllist)
{
foreach(XmlNode childNode in nod.ChildNodes)
{
// her ürünün childnode oldu
if(childNode.Name == "#text")
{
} else
{
var urun_resim = childNode.SelectSingleNode("//resimDosyasi").InnerText;
var urun_aciklama = childNode.SelectSingleNode("//aciklama").InnerText;
var urun_birim = childNode.SelectSingleNode("//birim").InnerText;
MessageBox.Show(urun_birim);
var urun_miktar = childNode.SelectSingleNode("//miktar").InnerText;
var urun_toplam = childNode.SelectSingleNode("//toplam").InnerText;
var urun = new Urun(urun_resim, urun_birim, urun_miktar, urun_aciklama);
lw_urunler.Items.Add(urun);
}
}
}
The problem is when I message box the //birim in foreach loop, it always writes the first one - 3,00((3 times). As you can see in XML, first is 3,00, the second is 5,00 and the third is 2,00 but it always writes the first one. I checked up a lot but I can't see the problem.

Try it without the //, e.g. childNode.SelectSingleNode("birim"). Two forward slashes mean the root of the XML document, and my guess is it's just always finding the first birim node starting from the root each time.

The // means to select nodes no matter where they are under the current context. Current context defaults to the root. To limit the results to those under the current child node follow this pattern (just add a dot):
var urun_resim = childNode.SelectSingleNode(".//resimDosyasi").InnerText;

Using xml linq :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication52
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
XDocument doc = XDocument.Load(FILENAME);
List<urun> uruns = doc.Descendants("urun").Select(x => new urun() {
resimDosyasi = (string)x.Element("resimDosyasi"),
aciklama = (string)x.Element("aciklama"),
birim = (string)x.Element("birim"),
miktar = (int)x.Element("miktar"),
toplam = (string)x.Element("toplam")
}).ToList();
}
}
public class urun
{
public string resimDosyasi { get; set; }
public string aciklama { get; set; }
public string birim { get; set; }
public int miktar { get; set; }
public string toplam { get; set; }
}
}

Another approach that would increase the readability and maintenance of your code would be to map the XML schema into an object model.
Doing so, you could easly load the XML data as follows:
XmlSerializer serializer = new XmlSerializer(typeof(Teklif));
using (FileStream fileStream = new FileStream(filename, FileMode.Open))
{
Teklif result = (Teklif)serializer.Deserialize(fileStream);
}
// Object model example
[XmlRoot("teklif")]
public class Teklif
{
[XmlElement()]
public bilgiler bilgiler { get; set; }
}
public class bilgiler
{
[XmlElement()] public string firma { get; set; }
[XmlElement()] public string aciklama { get; set; }
[XmlElement()] public string isim { get; set; }
[XmlElement()] public string telefon { get; set; }
[XmlElement()] public string eposta { get; set; }
[XmlArray()]
[XmlArrayItem("urun")]
public List<Urun> urunler { get; set; }
}
public class Urun
{
[XmlElement()] public string resimDosyasi { get; set; }
[XmlElement()] public string aciklama { get; set; }
[XmlElement()] public string birim { get; set; }
[XmlElement()] public int miktar { get; set; }
[XmlElement()] public string toplam { get; set; }
}

Related

How do i extract specific attributes while iterating through an XML document (XML Parsing) using C#

I am new to c# and therefore I hope that some of you can help me with this problem:
I have a long XML-file that consists of multiple nodes and attributes. I am looking for a method on how to iterate through the XML document while being able to set up a method to extract certain attributes of interest and then store those attributes in a array (the goal is to visualize them afterwards by storing in collection).
I have tried solving this in multiple ways, like for example by using get Xpath, deserialization and so forth, Unfortunately none of them work out, especially that <TeamData> appears more than once.
The XML-file looks like this:
- <SoccerFeed TimeStamp="20190818T190845+0100">
- <SoccerDocument Type="Result" detail_id="1" uID="f1059230">
- <MatchData>
- <TeamData Formation="433" Score="2" Side="Home" TeamRef="t239">
<Booking Card="Yellow" CardType="Yellow" EventID="6020960" EventNumber="1141" Min="13"
Period="FirstHalf" PlayerRef="p112340" Reason="Foul" Sec="31" Time="14"
TimeStamp="20190818T171443+0100" uID="b239-1" />
</TeamData>
- <TeamData TeamRef="t401" Side="Away" Score="1" Formation="433">
<Booking TimeStamp="20190818T182120+0100" uID="b401-1" Period="SecondHalf" Time="64"
Sec="15" Reason="Foul" PlayerRef="p229218" Min="63" EventNumber="2648"
EventID="708326435" CardType="Yellow" Card="Yellow"/>
</TeamData>
</MatchData>
</SoccerDocument
This is somewhat my idea at this point:
int totalC;
XmlDocument xmlDoc = new XmlDocument();
string XMLpath = Directory.GetCurrentDirectory() +
#"File.xml";
xmlDoc.Load(XMLpath);
XmlNodeList Clist = xmlDoc.GetElementsByTagName("TimeStamp");
totalC = Clist.Count;
for (int i = 0; i < Clist.Count; i++)
{
Console.WriteLine(Clist[i].InnerText.ToString());
}
Console.WriteLine(Environment.NewLine);
Console.WriteLine(totalC.ToString() + " hello");
Console.ReadLine();
I hope that my question is clear enough, thank you in advance!
You can do this easily with LINQ to XML
var doc = XDocument.Load(#"Test.xml");
var distinctResults = doc.Descendants("Booking")
.Select(element => element.Attribute("TimeStamp").Value)
.Distinct().ToArray();
Without LINQ to XML -
XmlDocument xmlDoc = new XmlDocument();
string XMLpath = #"Test.xml";
xmlDoc.Load(XMLpath);
List<string> attributes = new List<string>();
XmlNodeList nodes = xmlDoc.GetElementsByTagName("Booking");
foreach (XmlElement n in nodes)
{
XmlAttributeCollection attributesData = n.Attributes;
foreach (XmlAttribute at in atributesData)
{
if (at.LocalName.Contains("TimeStamp"))
{
attributes.Add(at.Value);
}
}
}
I think in this case you should be using Xml Serialization due to the number of properties and the arrays in the data
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
using System.IO;
using System.Globalization;
namespace ConsoleApplication1
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
string xml = File.ReadAllText(FILENAME);
StringReader sReader = new StringReader(xml);
XmlReader xReader = XmlReader.Create(sReader);
XmlSerializer serializer = new XmlSerializer(typeof(SoccerFeed));
SoccerFeed soccerFeed = (SoccerFeed)serializer.Deserialize(xReader);
}
}
public class SoccerFeed
{
private DateTime _TimeStamp { get; set; }
[XmlAttribute]
public string TimeStamp
{
get { return _TimeStamp.ToString("yyyyMMddTHHmmss+ffff"); }
set { _TimeStamp = DateTime.ParseExact(value, "yyyyMMddTHHmmss+ffff", CultureInfo.InvariantCulture); }
}
public SoccerDocument SoccerDocument { get; set; }
}
public class SoccerDocument
{
[XmlAttribute]
public int detail_id { get; set; }
[XmlAttribute]
public string uID { get; set; }
[XmlArray("MatchData")]
[XmlArrayItem("TeamData")]
public List<TeamData> teamData { get; set; }
}
public class TeamData
{
[XmlAttribute]
public int Formation { get; set; }
[XmlAttribute]
public int Score { get; set; }
[XmlAttribute]
public string Side { get; set; }
[XmlAttribute]
public string TeamRef { get; set; }
public Booking Booking { get; set; }
}
public class Booking
{
[XmlAttribute]
public string Card { get; set; }
[XmlAttribute]
public string CardType { get; set; }
[XmlAttribute]
public string EventID { get; set; }
[XmlAttribute]
public int EventNumber { get; set; }
[XmlAttribute]
public int Min { get; set; }
[XmlAttribute]
public string Period { get; set; }
[XmlAttribute]
public string PlayerRef { get; set; }
[XmlAttribute]
public string Reason { get; set; }
[XmlAttribute]
public int Sec { get; set; }
[XmlAttribute]
public int Time { get; set; }
private DateTime _TimeStamp { get; set; }
[XmlAttribute]
public string TimeStamp
{
get { return _TimeStamp.ToString("yyyyMMddTHHmmss+ffff"); }
set { _TimeStamp = DateTime.ParseExact(value, "yyyyMMddTHHmmss+ffff", CultureInfo.InvariantCulture); }
}
}
}

There is an error in XML document (2, 2) when desearlizing xml to c# object

XML
<?xml version="1.0" encoding="UTF-8"?>
<orgc:Organizations xmlns:orgc="urn:workday.com/connector/orgs" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<orgc:Organization>
<orgc:Organization_ID>SR1Code34</orgc:Organization_ID>
<orgc:Organization_Code>SR1Code34</orgc:Organization_Code>
<orgc:Organization_Type>Cost_Center_Hierarchy</orgc:Organization_Type>
<orgc:Organization_Name>LTL Services</orgc:Organization_Name>
<orgc:Organization_Description>LTL Services</orgc:Organization_Description>
<orgc:Organization_Subtype>ORGANIZATION_SUBTYPE-3-20</orgc:Organization_Subtype>
<orgc:Inactive>false</orgc:Inactive>
<orgc:Superior_Organization>DL2Code11</orgc:Superior_Organization>
</orgc:Organization>
<orgc:Organization>
<orgc:Organization_ID>SR1Code35</orgc:Organization_ID>
<orgc:Organization_Code>SR1Code35</orgc:Organization_Code>
<orgc:Organization_Type>Cost_Center_Hierarchy</orgc:Organization_Type>
<orgc:Organization_Name>Consolidation</orgc:Organization_Name>
<orgc:Organization_Description>Consolidation</orgc:Organization_Description>
<orgc:Organization_Subtype>ORGANIZATION_SUBTYPE-3-20</orgc:Organization_Subtype>
<orgc:Inactive>false</orgc:Inactive>
<orgc:Superior_Organization>DL2Code11</orgc:Superior_Organization>
</orgc:Organization>
</orgc:Organizations>
Class
[XmlRoot(ElementName = "Organizations", Namespace = "urn: workday.com/connector/orgs", IsNullable = true )]
public class CostCenterHierarchy
{
[XmlElement("orgc:Organization_ID")]
public string CostCenterHierarchyId { get; set; }
[XmlElement("orgc:Organization_Code")]
public string Code { get; set; }
[XmlElement("orgc:Organization_Name")]
public string Name { get; set; }
[XmlElement("orgc:Organization_Description")]
public string Description { get; set; }
[XmlElement("orgc:Organization_Subtype")]
public string Subtype { get; set; }
[XmlElement("orgc:Superior_Organization")]
public string ParentHierarchyId { get; set; }
}
Method to deseralize xml to c# class
private List<CostCenterHierarchy> ProcessCostCenterHierarchy(string filePath)
{
var costCenterHierarchyList = new List<CostCenterHierarchy>();
//var costCenterHierarchy = new CostCenterHierarchy();
XmlSerializer xmlSerializer = new XmlSerializer(typeof(List<CostCenterHierarchy>));
using (var reader = XmlReader.Create(filePath))
{
var test = xmlSerializer.Deserialize(reader);
}
return costCenterHierarchyList;
}
Error Message
Message = "There is an error in XML document (2, 2)."
InnerException = {"<Organizations xmlns='urn:workday.com/connector/orgs'> was not expected."}
I'm not sure where I am going wrong. Seems like it should be pretty easy but I've played around with this and keep getting the same error message. Any help would be much appreciated.
The code below works. You have an array and serialization doesn't like a list as the type. The Url "urn:workday.com/connector/orgs" the serializaer doesn't like and had to replace the "urn:" with "http://workday.com/connector/orgs".
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
namespace ConsoleApplication1
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
XmlReader reader = XmlReader.Create(FILENAME);
XmlSerializer serializer = new XmlSerializer(typeof(Organizations));
Organizations organizations = (Organizations)serializer.Deserialize(reader);
}
}
[XmlRoot(ElementName = "Organizations", Namespace = "http://workday.com/connector/orgs")]
public class Organizations
{
[XmlElement(ElementName = "Organization", Namespace = "http://workday.com/connector/orgs")]
public List<CostCenterHierarchy> organizations { get; set; }
}
public class CostCenterHierarchy
{
[XmlElement("Organization_ID")]
public string CostCenterHierarchyId { get; set; }
[XmlElement("Organization_Code")]
public string Code { get; set; }
[XmlElement("Organization_Name")]
public string Name { get; set; }
[XmlElement("Organization_Description")]
public string Description { get; set; }
[XmlElement("Organization_Subtype")]
public string Subtype { get; set; }
[XmlElement("Superior_Organization")]
public string ParentHierarchyId { get; set; }
}
}

Deserialize XML with XmlSerializer where parent and child have the same tag

I'm having difficulty parsing an XML string where the parent and child nodes have the same tag name. Obviously, I could replace the open/close tags with empty strings and parse with the code below, but that's not elegant.
I've searched and see that there are answers for how to do this with XDocument, but I specifically would like to do this with XmlSerializer (if possible).
Below is a minimal, reproducable example.
Example XML:
<AddJob>
<AddJob RequestStatus="OK" RequestMessage="Job successfuly added [testPrintServer.tif, PES_Carpet_16C_76.2 x 50.8 dpi_170517_Normal]" UUID="74ad5971-7baf-49ce-b85b-ee08188d5721" />
</AddJob>
Parsing code:
public class XmlHelper
{
public static T Deserialize<T>(string xml)
{
var serializer = new XmlSerializer(typeof(T));
T result;
using (var reader = new StringReader(xml))
{
result = (T)serializer.Deserialize(reader);
}
return result;
}
}
Data model:
[XmlRoot("AddJob")]
public class AddJob
{
[XmlAttribute]
public string RequestStatus { get; set; }
[XmlAttribute]
public string RequestMessage { get; set; }
[XmlAttribute("UUID")]
public string RipJobId { get; set; }
}
Calling code:
var addedJobResponse = XmlHelper.Deserialize<AddJob>(exampleXml);
Your data model doesn't match your xml structure.
Please use something like that:
[XmlRoot("AddJob")]
public class AddJob
{
[XmlElement(ElementName = "AddJob")]
public List<NestedAddJob> AddJobs { get; set; }
}
public class NestedAddJob
{
[XmlAttribute]
public string RequestStatus { get; set; }
[XmlAttribute]
public string RequestMessage { get; set; }
[XmlAttribute("UUID")]
public string RipJobId { get; set; }
}
The nested AddJob elements look like an array and you cannot have an array at the root. So add a Root class like code below :
using System;
using System.Collections.Generic;
using System.Collections;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
using System.IO;
namespace ConsoleApplication75
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
string xml = "<AddJob>" +
"<AddJob RequestStatus=\"OK\" RequestMessage=\"Job successfuly added [testPrintServer.tif, PES_Carpet_16C_76.2 x 50.8 dpi_170517_Normal]\" UUID=\"74ad5971-7baf-49ce-b85b-ee08188d5721\" />" +
"</AddJob>";
Root job = XmlHelper.Deserialize<Root>(xml);
}
}
public class XmlHelper
{
public static T Deserialize<T>(string xml)
{
var serializer = new XmlSerializer(typeof(T));
T result;
using (var reader = new StringReader(xml))
{
result = (T)serializer.Deserialize(reader);
}
return result;
}
}
[XmlRoot("AddJob")]
public class Root
{
public AddJob AddJob { get; set; }
}
public class AddJob
{
[XmlAttribute]
public string RequestStatus { get; set; }
[XmlAttribute]
public string RequestMessage { get; set; }
[XmlAttribute("UUID")]
public string RipJobId { get; set; }
}
}

deserialize xml into inherited classes from base class

I have the following xml structure:
<Root1>
<name>Name1</name>
<company>Comp1</company>
<url>site.com</url>
<elements>
<element id="12" type="1">
<url>site1.com</url>
<price>15000</price>
...
<manufacturer_warranty>true</manufacturer_warranty>
<country_of_origin>Япония</country_of_origin>
</element>
<element id="13" type="2">
<url>site2.com</url>
<price>100</price>
...
<language>lg</language>
<binding>123</binding>
</element>
</elements>
</Root1>
I need to deserialize this xml into an object. You can see the element contains some equals field: url and price.
I would like to move these fields into a parent class and then inherit this class from other classes.
I created the class Root1:
namespace app1
{
[Serializable]
public class Root1
{
[XmlElement("name")]
public string Name { get; set; }
[XmlElement("company")]
public string Company { get; set; }
[XmlElement("url")]
public string Url { get; set; }
[XmlElement("elements")]
public List<Element> ElementList { get; set; }
}
}
and then I created base class for Element:
[Serializable]
public class Element
{
[XmlElement("url")]
public string Url { get; set; }
[XmlElement("price")]
public string Price { get; set; }
}
and then I inherited this class from other classes:
[Serializable]
public class Element1 : Element
{
[XmlElement("manufacturer_warranty")]
public string mw { get; set; }
[XmlElement("country_of_origin")]
public string co { get; set; }
}
[Serializable]
public class Element2 : Element
{
[XmlElement("language")]
public string lg { get; set; }
[XmlElement("binding")]
public string bind { get; set; }
}
When I deserialize this xml to object Root1 I get the object - it is ok.
But the List of Elements contains only Element objects not Element1 and Element2 objects.
How I do deserialize this xml so list of Elements contains Element1 and Element2 objects?
#netwer It is not working for you because the code suggested above generates the xml (below) that does not match with the one you use for deserialization (see how it specifies derived types in for element).
<?xml version="1.0" encoding="utf-8"?>
<Root1>
<name>Name1</name>
<company>Comp1</company>
<url>site.com</url>
<elements>
<element d3p1:type="Element1" xmlns:d3p1="http://www.w3.org/2001/XMLSchema-instance">
<url>site1.com</url>
<price>15000</price>
<manufacturer_warranty>true</manufacturer_warranty>
<country_of_origin>Япония</country_of_origin>
</element>
<element d3p1:type="Element2" xmlns:d3p1="http://www.w3.org/2001/XMLSchema-instance">
<url>site2.com</url>
<price>100</price>
<language>lg</language>
<binding>123</binding>
</element>
</elements>
</Root1>
So you will either have to match this format with source xml (change code or API that returns this xml data) or take another approach. Even if you manage to do with former one you have to find a way to access Element1 or Element2 specific properties.
newRoot1.Elements.ElementList[i] will always let you access only price and url since your list is of Element type. Although run time type of ElementList[i] will be Element1 or Element2, how will you detect that?
Here I suggest alternative approach. Irrespective of whether your application (client) generates this xml or the server which returns it on hitting API, you should be able to gather information on all the fields applicable to an 'element' object. If it is your code you know it already, if it is an API there must be a document for it. This way you only have to create one 'Element' (no derived classes) and put proper checks (mostly string.IsNullOrEmpty()) before accessing Element class property values in your code. Only the properties that are present in your xml 'element' element will be considered rest will be set to NULL for that instance.
[Serializable]
public class Element
{
[XmlElement("url")]
public string Url { get; set; }
[XmlElement("price")]
public string Price { get; set; }
[XmlElement("manufacturer_warranty")]
public string mw { get; set; }
[XmlElement("country_of_origin")]
public string co { get; set; }
[XmlElement("language")]
public string lg { get; set; }
[XmlElement("binding")]
public string bind { get; set; }
}
I think you should use XmlIncludeAttribute like this:
[XmlInclude(typeof(Element1))]
public class Element
{
}
Here is xml and code. I like to first serialize with test data, then deserialize.
<?xml version="1.0" encoding="utf-8"?>
<Root1>
<name>Name1</name>
<company>Comp1</company>
<url>site.com</url>
<element d2p1:type="Element1" xmlns:d2p1="http://www.w3.org/2001/XMLSchema-instance">
<url>site1.com</url>
<price>15000</price>
<manufacturer_warranty>true</manufacturer_warranty>
<country_of_origin>Япония</country_of_origin>
</element>
<element d2p1:type="Element2" xmlns:d2p1="http://www.w3.org/2001/XMLSchema-instance">
<url>site2.com</url>
<price>100</price>
<language>lg</language>
<binding>123</binding>
</element>
</Root1>
Code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
using System.IO;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
string FILENAME = #"c:\temp\test.xml";
Root1 root1 = new Root1() {
Name = "Name1",
Company = "Comp1",
Url = "site.com",
ElementList = new List<Element>() {
new Element1() {
Url = "site1.com",
Price = "15000",
mw = "true",
co = "Япония"
},
new Element2() {
Url = "site2.com",
Price = "100",
lg = "lg",
bind = "123"
}
}
};
XmlSerializer serializer = new XmlSerializer(typeof(Root1));
StreamWriter writer = new StreamWriter(FILENAME);
XmlSerializerNamespaces _ns = new XmlSerializerNamespaces();
_ns.Add("", "");
serializer.Serialize(writer, root1, _ns);
writer.Flush();
writer.Close();
writer.Dispose();
XmlSerializer xs = new XmlSerializer(typeof(Root1));
XmlTextReader reader = new XmlTextReader(FILENAME);
Root1 newRoot1 = (Root1)xs.Deserialize(reader);
}
}
[XmlRoot("Root1")]
public class Root1
{
[XmlElement("name")]
public string Name { get; set; }
[XmlElement("company")]
public string Company { get; set; }
[XmlElement("url")]
public string Url { get; set; }
[XmlElement("element")]
public List<Element> ElementList { get; set; }
}
[XmlInclude(typeof(Element1))]
[XmlInclude(typeof(Element2))]
[XmlRoot("element")]
public class Element
{
[XmlElement("url")]
public string Url { get; set; }
[XmlElement("price")]
public string Price { get; set; }
}
[XmlRoot("element1")]
public class Element1 : Element
{
[XmlElement("manufacturer_warranty")]
public string mw { get; set; }
[XmlElement("country_of_origin")]
public string co { get; set; }
}
[XmlRoot("element2")]
public class Element2 : Element
{
[XmlElement("language")]
public string lg { get; set; }
[XmlElement("binding")]
public string bind { get; set; }
}
}
Code below matches better with your posted XML. You need to compare the generated xml with your xml.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
using System.IO;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
string FILENAME = #"c:\temp\test.xml";
Root1 root1 = new Root1()
{
Name = "Name1",
Company = "Comp1",
Url = "site.com",
cElement = new Elements() {
ElementList = new List<Element>() {
new Element1() {
Url = "site1.com",
Price = "15000",
mw = "true",
co = "Япония"
},
new Element2() {
Url = "site2.com",
Price = "100",
lg = "lg",
bind = "123"
}
}
}
};
XmlSerializer serializer = new XmlSerializer(typeof(Root1));
StreamWriter writer = new StreamWriter(FILENAME);
XmlSerializerNamespaces _ns = new XmlSerializerNamespaces();
_ns.Add("", "");
serializer.Serialize(writer, root1, _ns);
writer.Flush();
writer.Close();
writer.Dispose();
XmlSerializer xs = new XmlSerializer(typeof(Root1));
XmlTextReader reader = new XmlTextReader(FILENAME);
Root1 newRoot1 = (Root1)xs.Deserialize(reader);
}
}
[XmlRoot("Root1")]
public class Root1
{
[XmlElement("name")]
public string Name { get; set; }
[XmlElement("company")]
public string Company { get; set; }
[XmlElement("url")]
public string Url { get; set; }
[XmlElement("elements")]
public Elements cElement { get; set; }
}
[XmlRoot("elements")]
public class Elements
{
[XmlElement("element")]
public List<Element> ElementList { get; set; }
}
[XmlInclude(typeof(Element1))]
[XmlInclude(typeof(Element2))]
[XmlRoot("element", Namespace = "")]
public class Element
{
[XmlElement("url")]
public string Url { get; set; }
[XmlElement("price")]
public string Price { get; set; }
}
[XmlRoot("element1", Namespace = "")]
public class Element1 : Element
{
[XmlElement("manufacturer_warranty")]
public string mw { get; set; }
[XmlElement("country_of_origin")]
public string co { get; set; }
}
[XmlRoot("element2", Namespace = "")]
public class Element2 : Element
{
[XmlElement("language")]
public string lg { get; set; }
[XmlElement("binding")]
public string bind { get; set; }
}
}​

C# Deserializing nested xml

I have the following code to deseriaze an xml string in C#.
Everything works fine and I am able to deserialize it to an object. However, the ProjectNode value is always empty.
Can someone please help me make this code work or point out what am I missing?
The sample XML has been included in the code below.
using System;
using System.Collections.Generic;
using System.IO;
using System.Xml;
using System.Xml.Serialization;
namespace DeserializeSample
{
class Program
{
static string XML = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?><response clientos=\"Windows\" datetimepattern=\"M/d/yyyy h:mm:ss a\"><info><![CDATA[<?xml version=\"1.0\" encoding=\"UTF-8\"?><transaction loglevel=\"0\" type=\"response\"><arguments><argument name=\"id\">1</argument><argument name=\"foredit\">True</argument><argument name=\"ScheduleOn\">Estimated</argument><argument name=\"xml\"><Project xmlns=\"http://schemas.microsoft.com/project\"><UID>0</UID><ID>0</ID></Project></argument></arguments></transaction>]]></info></response>";
static void Main(string[] args)
{
ProjectResponse projectResponse = CreateFromXml(XML, typeof(ProjectResponse)) as ProjectResponse;
}
public static object CreateFromXml(string data, Type msfRequestResponseType)
{
object projectResponse = null;
try
{
XmlSerializer deserializer = new XmlSerializer(msfRequestResponseType, "");
XmlReaderSettings settings = new XmlReaderSettings() { ProhibitDtd = true };
// We have content in the part so create xml reader and load the xml into XElement.
using (XmlReader reader = XmlReader.Create(new StringReader(data), settings))
{
projectResponse = deserializer.Deserialize(reader);
}
}
catch (Exception Ex)
{
throw;
}
return projectResponse;
}
}
[XmlRoot("response")]
[Serializable]
public class ProjectResponse
{
[XmlAnyAttribute()]
public XmlAttribute[] ResponseAttributes { get; set; }
[XmlElement("info")]
public ProjectResponseInfoTag InfoTag { get; set; }
public class ProjectResponseInfoTag
{
private string infoText = string.Empty;
[XmlText]
public string InfoText
{
get { return infoText; }
set
{
infoText = value;
Transaction = Program.CreateFromXml(infoText, typeof(ProjectTransaction)) as ProjectTransaction;
}
}
[XmlElement("transaction")]
public ProjectTransaction Transaction { get; set; }
[XmlRoot("transaction")]
public class ProjectTransaction
{
[XmlAnyAttribute]
public XmlAttribute[] TransactionAttributes { get; set; }
[XmlElement("arguments")]
public ProjectArguments Arguments { get; set; }
public class ProjectArguments
{
[XmlElement("argument")]
public List<ProjectArgument> ArgList { get; set; }
public class ProjectArgument
{
[XmlAttribute("name")]
public string Name { get; set; }
[XmlText]
public string ArgValue { get; set; }
[XmlElement("Project")]
public Project ProjectNode { get; set; }
public class Project
{
[XmlAnyElement()]
public XmlElement[] ProjectElements { get; set; }
[XmlAnyAttribute()]
public XmlAttribute[] ProjectAttributes { get; set; }
}
}
}
}
}
}
}
Xml namespaces; try
[XmlElement("Project", Namespace="http://schemas.microsoft.com/project")]

Categories