Writing into xml with more than one lines - c#

I am developing a c# application.
I need to write company-product details in this form. One company may have more than one product and one xml file may contain only 1 company. So one xml file for every company.
<?xml version="1.0" encoding="utf-8" ?>
<list>
<CompanyName>Test</CompanyName>
<CompanyID>TestID</CompanyID>
<Product>
<ProductName>Prod</ProductName>
<ProductID>ProdID</ProductID>
<Expire>10.10.2010</Expire>
</Product>
<Product>
<ProductName>Prod2</ProductName>
<ProductID>ProdID2</ProductID>
<Expire>11.10.2010</Expire>
</Product>
<Product>
<ProductName>Prod3</ProductName>
<ProductID>ProdID3</ProductID>
<Expire>12.10.2010</Expire>
</Product>
</list>
How can i make one xml file to have 3 attributes in c#?
I would appreciate your helps.
Regards

If you are asking how to write an xml file in C# then you have write a class provide xml attributes to class and its properties, and then serialize the class.
Instance of the class with all its data will be serialized to xml:
Here is an example in your situation.
[XmlType(TypeName = "CompanyXml")]
public class Company : ISerializable
{
[XmlElement("Product")]
public List<Product> ListProduct { get; set; }
[XmlElement("CompanyName")]
public string CompanyName { get; set; }
[XmlElement("CompanyID")]
public string CompanyID { get; set; }
}
Product class looks like:
[XmlType(TypeName = "Product")]
public class Product : ISerializable
{
[XmlElement("ProductName")]
public string ProductName { get; set; }
[XmlElement("ProductID")]
public string ProductID { get; set; }
[XmlElement("Expires")]
public string Expires { get; set; }
}
Serialization code could follow as:
using (StringWriter stringWriter = new StringWriter())
{
XmlSerializer serializer = new XmlSerializer(typeof(Company));
serializer.Serialize(stringWriter, companyInstance);
XmlDocument xDoc = new XmlDocument();
xDoc.LoadXml(stringWriter.ToString());
}

Related

How do you deserialize XML with incremented ID on the collection?

I have a set of large XML files with various sections in them.
As an example file I have mocked this up which serializes and deserializes just fine if I don't have the appended counter of 1, 2, 3... etc.
<?xml version="1.0" encoding="utf-16"?>
<employees xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<category name="TestCategory" baseicon="0" decalicon="0">
<EmployeeList1>
<name type="string">Peter Parker</name>
<age type="number">25</age>
</EmployeeList1>
<EmployeeList2>
<name type="string">J.J. Jameson</name>
<age type="number">57</age>
</EmployeeList2>
</category>
</employees>
However, when I have the incremented elements in the collection I get back no objects in the EmployeeList collection but will get back the overall Employees object.
So all the objects within the EmployeeList elements have the same structure overall although some will have optional fields like, let's say "homeowner".
[XmlRoot(ElementName = "category")]
public class Category
{
[XmlAttribute(AttributeName = "name")]
public string Name;
[XmlAttribute(AttributeName = "baseicon")]
public int Baseicon;
[XmlAttribute(AttributeName = "decalicon")]
public int Decalicon;
[XmlElement]
public List<Employee> EmployeeList { get; set; }
public Category()
{
}
}
And the Employee class looks like this:
[XmlRoot(ElementName = "employees")]
public class Employees
{
[XmlElement(ElementName = "category")]
public Category Category;
public Employees()
{
}
}
[XmlRoot(ElementName = "employee")]
public class Employee
{
[XmlElement(ElementName = "name")]
public Name Name { get; set; }
[XmlElement(ElementName = "age")]
public Age Age { get; set; }
}
Then, of course the follow up is how to serialize a collection of elements with an incremented ID?
I can offer a custom XmlReader that will replace the specified element names on the fly.
public class ReplacingXmlReader : XmlTextReader
{
private readonly string _nameToReplace;
public ReplacingXmlReader(string url, string nameToReplace)
: base(url)
{
_nameToReplace = nameToReplace;
}
// Define the remaining constructors here.
public override string LocalName
{
get
{
if (base.LocalName.StartsWith(_nameToReplace))
return _nameToReplace;
return base.LocalName;
}
}
}
Usage is easy:
var xs = new XmlSerializer(typeof(Employees));
using var reader = new ReplacingXmlReader("test.xml", "EmployeeList");
var employees = (Employees)xs.Deserialize(reader);
If necessary, you can make a list of element names to replace.
Using serial numbers as part of the element name is really bad XML design, and the best way of dealing with badly designed XML is often to put it through an XSLT transformation that turns it into something more manageable, before doing any further processing. In this case you might simply strip off the numeric suffixes, because they're completely redundant.
In XSLT 3.0 that would be:
<xsl:transform version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:mode on-no-match="shallow-copy">
<xsl:template match="*[starts-with(local-name(), 'EmployeeList'>
<EmployeeList>
<xsl:apply-templates/>
</EmployeeList>
</xsl:template>
</xsl:transform>

Cannot deserialize sub-elements to list of objects

I am having problems serializing elements of an XML to a list of objects.
This is the XML:
<result>
<stats>
<numitemsfound>1451</numitemsfound>
<startfrom>0</startfrom>
</stats>
<items>
<item>
<id>1</id>
<markedfordeletion>0</markedfordeletion>
<thumbsrc>
</thumbsrc>
<thumbsrclarge>
</thumbsrclarge>
...
<datasource>65</datasource>
<data>
<amount>100</amount>
<kj>389</kj>
<kcal>92.91</kcal>
<fat_gram>0.2</fat_gram>
<fat_sat_gram>-1</fat_sat_gram>
<kh_gram>20.03</kh_gram>
</data>
<servings>
<serving>
<serving_id>386</serving_id>
<weight_gram>150</weight_gram>
</serving>
</servings>
</item>
</result>
The classes I prepared for serialization are
[XmlType("item")]
public class Item
{
[XmlAttribute("id")]
public string id { get; set; }
[XmlAttribute("markedfordeletion")]
public string markedfordeletion { get; set; }
...
[XmlAttribute("datasource")]
public string datasource { get; set; }
[XmlElement("data")]
public Data data { get; set; }
[XmlElement("servings")]
public List<Serving> servings { get; set; }
}
}
This is how I try to serialize the xml
public void ParseSearch(string xml)
{
XmlSerializer serializer = new XmlSerializer(typeof(List<Item>), new XmlRootAttribute("item"));
StringReader stringReader = new StringReader(xml);
var productList = (List<Item>)serializer.Deserialize(stringReader);
}
But I get the error ----> System.InvalidOperationException : <result xmlns=''> was not expected. Can you please help me solve this problem?
You have to use a serializer which serializes an instance of result, not of type List:
XmlSerializer serializer = new XmlSerializer(typeof(Result), new XmlRootAttribute("result")); //whatever `Result` actually is as type).
You canĀ“t serialize and de-serialize just parts of a document, either the whole one or nothing at all.
So you need a root-type:
[XmlRoot("result")]
public class Result
{
public Stats Stats {get; set;}
[XmlArray("items")]
[XmlArrayItem("item")]
public List<Item> Items { get; set; }
}

How to deserialize an XML with a nested array elements?

Deserialization of XML file with nested array of elements
I've searched but can't see any helpful examples.
this is my XML sample:
<trans>
<orderNo>0001</orderNo>
<orderDate>08/07/2014</orderDate>
<orders>
<item>
<itemName>item1</itemName>
<itemAmount>200</itemAmount>
<itemMeasures>
<measure>each</measure>
<measure>case</measure>
</itemMeasures>
</item>
<item>
<itemName>item2</itemName>
<itemAmount>100</itemAmount>
<itemMeasures>
<measure>each</measure>
<measure>case</measure>
</itemMeasures>
</item>
</orders>
</trans>
You must create classes for each of the structures you have in the XML and then using XmlSerializer and the method Deserialize of the object from that class you can create nested arrays with the values. If you want code and example, please edit your post with the full xml structure.
See the example below for part of your xml:
[XmlType("trans")]
public class Trans
{
[XmlElement("orderNo")]
public string OrderNo { get; set; }
[XmlElement("orderDate")]
public string OrderDate { get; set; }
[XmlArray("orders")]
public HashSet<Item> Orders { get; set; }
}
[XmlType("item")]
public class Item
{
[XmlElement("itemName")]
public string ItemName { get; set; }
[XmlElement("itemAmount")]
public string ItemAmount { get; set; }
}
The the Deserialization code is:
XmlSerializer mySerializer = new XmlSerializer(typeof(Trans[]), new XmlRootAttribute("trans"));
using (FileStream myFileStream = new FileStream("XmlFile.xml", FileMode.Open))
{
Trans[] r;
r = (Trans[])mySerializer.Deserialize(myFileStream);
}

Deserializing an XML document with the root being a list

I have an XML document provided to me externally that I need to import into my application. The document is badly written, but not something I can really do much about.
<?xml version="1.0" encoding="iso-8859-1"?>
<xml>
<Items>
<Property1 />
<Property2 />
...
</Items>
<Items>
<Property1 />
<Property2 />
...
</Items>
...
</xml>
How should I go about using the XmlSerializer for this?
It doesn't seem to matter what class setup I use, or wether I put XmlRoot(ElementName="xml") on my base class it always says that the <xml xmlns=''> is unexpected.
Edit: Added the C# code I am using
[XmlRoot(ElementName = "xml")]
public class Container
{
public List<Items> Items { get; set; }
}
public class Items
{
public short S1 { get; set; }
public short S2 { get; set; }
public short S3 { get; set; }
public short S4 { get; set; }
public short S5 { get; set; }
public short S6 { get; set; }
public short S7 { get; set; }
}
public class XMLImport
{
public Container Data{ get; private set; }
public static XMLImport DeSerializeFromFile(string fileName)
{
XMLImport import = new XMLImport();
XmlSerializer serializer = new XmlSerializer(typeof(Container));
using (StreamReader reader = new StreamReader(fileName))
import.Data = (Container)serializer.Deserialize(reader);
return import;
}
}
Say you have a class Items maps to each <Items> node:
public class Items
{
public string Property1 { get; set; }
public string Property2 { get; set; }
}
You can deserialize your list of Items like this:
var doc = XDocument.Parse(
#"<?xml version=""1.0"" encoding=""iso-8859-1""?>
<xml>
<Items>
<Property1 />
<Property2 />
</Items>
<Items>
<Property1 />
<Property2 />
</Items>
</xml>");
var serializer = new XmlSerializer(typeof(List<Items>), new XmlRootAttribute("xml"));
List<Items> list = (List<Items>)serializer.Deserialize(doc.CreateReader());
The root of your XML is not a List, the root of your xml is the <xml> node I think you are just confused by its name :)
please visit the following link, It has many good answers voted by many people.
Here is the link: How to Deserialize XML document
Error Deserializing Xml to Object - xmlns='' was not expected
Simply take off the Namespace =:
[XmlRoot("xml"), XmlType("xml")]
public class RegisterAccountResponse {...}

Deserialize XML to object (need to return a list of objects)

Started practicing with XML and C# and I have an error message of "There is an error in XML document (3,2)". After looking at the file, I can't see anything wrong with it (Mind you, I probably missed something since I'm a noob). I'm using a Console Application for C# right now. I'm trying to return a list of Adventurers and just a side note, the GEAR element is optional. Here is what I have so far:
XML File - Test1
<?xml version="1.0" encoding="utf-8"?>
<Catalog>
<Adventurer>
<ID>001</ID>
<Name>John Smith</Name>
<Address>123 Fake Street</Address>
<Phone>123-456-7890</Phone>
<Gear>
<Attack>
<Item>
<IName>Sword</IName>
<IPrice>15.00</IPrice>
</Item>
<Item>
<IName>Wand</IName>
<IPrice>20.00</IPrice>
</Item>
</Attack>
<Defense>
<Item>
<IName>Shield</IName>
<IPrice>5.00</IPrice>
</Item>
</Defense>
</Gear>
</Adventurer>
<Adventurer>
<ID>002</ID>
<Name>Guy noone likes</Name>
<Address>Some Big House</Address>
<Phone>666-666-6666</Phone>
<Gear></Gear>
</Adventurer>
</Catalog>
C# Classes
public class Catalog
{
List<Adventurer> Adventurers { get; set; }
}
public class Adventurer
{
public int ID { get; set; }
public string Name { get; set; }
public string Address { get; set; }
public string Phone { get; set; }
public Gear Gear { get; set; }
}
public class Gear
{
public List<Item> Attack { get; set; }
public List<Item> Defense { get; set; }
}
public class Item
{
public string IName { get; set; }
public decimal IPrice { get; set; }
}
Serialize Function - Where the Problem Occurs at Line 5
Catalog obj = null;
string path = #"C:\Users\Blah\Desktop\test1.xml";
XmlSerializer serializer = new XmlSerializer(typeof(Catalog));
StreamReader reader = new StreamReader(path);
obj = (Catalog)serializer.Deserialize(reader);
reader.Close();
Console.ReadLine();
The issue is the list of Adventurers in Catalog:
<?xml version="1.0" encoding="utf-8"?>
<Catalog>
<Adventurers> <!-- you're missing this -->
<Adventurer>
</Adventurer>
...
<Adventurer>
</Adventurer>
</Adventurers> <!-- and missing this -->
</Catalog>
You don't have the wrapping element for the Adventurers collection.
EDIT: By the way, I find the easiest way to build the XML structure and make sure it's compatible is to create the object(s) in C#, then run through the built-in XmlSerializer and use its XML output as a basis for any XML I create rather than forming it by hand.
First, "Adventurers" property is not public, it's inaccessible, I think that the best way to find the error is to serialize your object and then compare the result with your xml file.
Your XML doesn't quite line up with your objects... namely these two...
public string City { get; set; }
and
<Address>123 Fake Street</Address>
Change City to Address or vice versa and it should fix the problem.
Edit: Got this to work in a test project, combination of all our answers...
Add <Adventurers> tag after <Catalog> (and </Adventurers> before </Catalog>) and change
List<Adventurer> Adventurers { get; set; }
to
public List<Adventurer> Adventurers { get; set; }
and it works properly for me.
I was able to get your xml to deserialize with a couple minor changes (namely the public qualifier on Adventurer).
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Xml.Serialization;
namespace TempSandbox
{
[XmlRoot]
public class Catalog
{
[XmlElement("Adventurer")]
public List<Adventurer> Adventurers;
private readonly static Type[] myTypes = new Type[] { typeof(Adventurer), typeof(Gear), typeof(Item) };
private readonly static XmlSerializer mySerializer = new XmlSerializer(typeof(Catalog), myTypes);
public static Catalog Deserialize(string xml)
{
return (Catalog)Utils.Deserialize(mySerializer, xml, Encoding.UTF8);
}
}
[XmlRoot]
public class Adventurer
{
public int ID;
public string Name;
public string Address;
public string Phone;
[XmlElement(IsNullable = true)]
public Gear Gear;
}
[XmlRoot]
public class Gear
{
public List<Item> Attack;
public List<Item> Defense;
}
[XmlRoot]
public class Item
{
public string IName;
public decimal IPrice;
}
}
I'm using [XmlElement("Adventurer")] because the xml element names don't exactly match the class property names.
NOTE: I'm using a generic deserialization utility i already had on hand .

Categories