XML serialize multiple elements with same name without namespace - c#

I have the following class which I'm trying to serialize. And I have two arrays with the same data type. I know that if we need more than one element to have the same name the namespace has be different. But there a workaround to remove those namespaces altogether.
[XmlRoot]
public class Album
{
public string Title { get; set; }
public string Description { get; set;}
public int CoverImgIndx { get; set; }
[XmlElement(ElementName ="Element", Namespace ="www.image.com")]
public Image[] Images { get; set; }
[XmlElement(ElementName ="Element", Namespace ="www.cover.com")]
public Image[] Cover { get; set; }
}
public class Image
{
public int indx { get; set; }
public string filepath { get; set; }
}
And I'm using XmlSerializer to serialize this.
public class Program
{
public static void Main()
{
var album = new Album
{
Title = "Album Title",
Description = "Some explanation.",
CoverImgIndx = 2,
Images = new Image[] {
new Image { indx = 0, filepath = #"C:\Images\file1.jpg" },
new Image { indx = 1, filepath = #"C:\Images\file2.png" },
new Image { indx = 2, filepath = #"C:\Images\file3.jpg" }
},
Cover = new Image[] {
new Image { indx = 0, filepath = #"C:\Images\cover1.jpg" }
}
};
XmlSerializer serializer = new XmlSerializer(typeof(Album));
serializer.Serialize(Console.Out, album);
}
}
The output i'm getting there is a namespace for image element. is there way to remove namespace without having to remove Images and Cover shareing the same element name.
<?xml version="1.0" encoding="utf-16"?>
<Album xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Title>Album Title</Title>
<Description>Some explanation.</Description>
<CoverImgIndx>2</CoverImgIndx>
<Element xmlns="www.image.com">
<indx>0</indx>
<filepath>C:\Images\file1.jpg</filepath>
</Element>
<Element xmlns="www.image.com">
<indx>1</indx>
<filepath>C:\Images\file2.png</filepath>
</Element>
<Element xmlns="www.image.com">
<indx>2</indx>
<filepath>C:\Images\file3.jpg</filepath>
</Element>
<Element xmlns="www.cover.com">
<indx>0</indx>
<filepath>C:\Images\cover1.jpg</filepath>
</Element>
</Album>
The output i'm looking for
<?xml version="1.0" encoding="utf-16"?>
<Album xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Title>Album Title</Title>
<Description>Some explanation.</Description>
<CoverImgIndx>2</CoverImgIndx>
<Element>
<indx>0</indx>
<filepath>C:\Images\file1.jpg</filepath>
</Element>
<Element>
<indx>1</indx>
<filepath>C:\Images\file2.png</filepath>
</Element>
<Element>
<indx>2</indx>
<filepath>C:\Images\file3.jpg</filepath>
</Element>
<Element>
<indx>0</indx>
<filepath>C:\Images\cover1.jpg</filepath>
</Element>
</Album>

Related

c# - how to deserialize only part of xml file

I have a xml:
<query xmlns='http://jabber.org/protocol/disco#info'>
<identity category='store'
type='file'
name='HTTP File Upload' />
<feature var='urn:xmpp:http:upload:0' />
<x type='result' xmlns='jabber:x:data'>
<field var='FORM_TYPE' type='hidden'>
<value>urn:xmpp:http:upload:0</value>
</field>
<field var='max-file-size'>
<value>5242880</value>
</field>
</x>
</query>
I need to get data only from <value> tags. In a result I'd like to get List<string>.
How to do this using System.Xml.Serialization?
Thanks for help
Please do your own thorough research before posting a question. Here are a few methods, your XML has namespaces(Xmlns) too so you need to consider that, go to the source credit for more examples.
- Method XML Namespace (you will most likely need this method)
https://techoctave.com/c7/posts/113-c-reading-xml-with-namespace
- Method XMLnode
`
XmlDocument doc = new XmlDocument();
doc.Load(Path);
XmlNodeList elemList = doc.GetElementsByTagName(...);
for (int i = 0; i < elemList.Count; i++)
{
string attrVal = elemList[i].Attributes["SuperString"].Value;
}
`
- Method Serialization
`
using System;
using System.IO;
using System.Text;
using System.Xml.Serialization;
namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
var title = new Title() { Id = 3, Value = "something" };
var serializer = new XmlSerializer(typeof(Title));
var stream = new MemoryStream();
serializer.Serialize(stream, title);
stream.Flush();
Console.Write(new string(Encoding.UTF8.GetChars(stream.GetBuffer())));
Console.ReadLine();
}
}
public class Title
{
[XmlAttribute("id")]
public int Id { get; set; }
[XmlText]
public string Value { get; set; }
}
}
`
Source Credit:
Serialize a C# class to XML with attributes and a single value for the class
with-attributes-and-a-single-value-for-the-clas
Read XML Attribute using XmlDocument
xmldocument
Thanks Deleted for your response but I relized that I need data from <field> and <value>
<field var='FORM_TYPE' type='hidden'>
<value>urn:xmpp:http:upload:0</value>
Fortunetly I figured it out by myself:
[XmlType("field")]
public class Field
{
[XmlAttribute("var")]
public string Var { get; set; }
[XmlElement("value")]
public string Value { get; set; }
}
[XmlType("query")]
public class DiscoFileInfo
{
[XmlArray("x",Namespace = "jabber:x:data")]
[XmlArrayItem("field", typeof(Field))]
public List<Field> Fields { get; set; }
}
XmlSerializer xmlSerializer = new XmlSerializer(typeof(DiscoFileInfo), "http://jabber.org/protocol/disco#info");

XmlDocument - How to get all values from multiple nodes

Here is my sample XML file:
<Main>
<Person>
<Name>Božena</Name>
<Surname>Němcová</Surname>
<Gender>Female</Gender>
<OrderNum>18</OrderNum>
<BirthDate>04.02.1820</BirthDate>
</Person>
<Person>
<Name>Jan</Name>
<Surname>Žižka</Surname>
<Gender>Male</Gender>
<OrderNum>7</OrderNum>
<BirthDate>19.09.1360</BirthDate>
</Person>
<Person>
<Name>Che</Name>
<Surname>Guevara</Surname>
<Gender>Male</Gender>
<OrderNum>27</OrderNum>
<BirthDate>14.06.1928</BirthDate>
</Person>
<Person>
<Name>Antonie</Name>
<Surname>de Saint-Exupéry</Surname>
<Gender>Male</Gender>
<OrderNum>15</OrderNum>
<BirthDate>29.06.1900</BirthDate>
</Person>
</Main>
Here is a code which I want to use to get a list of all values of Name element:
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load("PersonWrite.xml");
XmlNodeList data = xmlDoc.SelectNodes("Main/Person/Name");
The problem is that I'm only getting a value from the first Person element.
I like using deserialisation, it's a lot easier to work with.
using System;
using System.Xml.Serialization;
using System.IO;
public class Main
{
[XmlElement("Person")]
public Person[] People { get; set; }
}
public class Person
{
public string Name { get; set; }
public string Surname { get; set; }
public string Gender { get; set; }
public int OrderNum { get; set; }
public string BirthDate { get; set; }
}
public class Program
{
public static void Main()
{
var xmlString = #"<Main>
<Person>
<Name>Božena</Name>
<Surname>Němcová</Surname>
<Gender>Female</Gender>
<OrderNum>18</OrderNum>
<BirthDate>04.02.1820</BirthDate>
</Person>
<Person>
<Name>Jan</Name>
<Surname>Žižka</Surname>
<Gender>Male</Gender>
<OrderNum>7</OrderNum>
<BirthDate>19.09.1360</BirthDate>
</Person>
<Person>
<Name>Che</Name>
<Surname>Guevara</Surname>
<Gender>Male</Gender>
<OrderNum>27</OrderNum>
<BirthDate>14.06.1928</BirthDate>
</Person>
<Person>
<Name>Antonie</Name>
<Surname>de Saint-Exupéry</Surname>
<Gender>Male</Gender>
<OrderNum>15</OrderNum>
<BirthDate>29.06.1900</BirthDate>
</Person>
</Main>";
var serializer = new XmlSerializer(typeof (Main));
Main main = null;
using (var reader = new StringReader(xmlString))
{
main = (Main)serializer.Deserialize(reader);
}
if (main == null)
{
return;
}
Console.WriteLine(main.People.Length);
}
}
Output:
4
I would go through the Child Nodes of Main Node
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load("PersonWrite.xml");
XmlNodeList root = xmlDoc.SelectNodes("Main");
foreach (XmlNode xnode in root.ChildNodes)
{
//get data from xnode
}

Multiple, identical elements in the same C# DTO

I am trying to create a WCF-service, which can return me an XML document looking something like this:
<alert>
<identifier>SecretID</identifier>
<info>
<valueName>Name1</valueName>
<value>Info1</value>
</info>
<info>
<valueName>Name2</valueName>
<value>Info2</value>
</info>
</alert>
The DTO of this file would look something like this:
[DataContract(Name = "alert", Namespace = "")]
public class Alert
{
[DataMember(Name = "identifier")]
public string identifier { get; set; }
[DataMember(Name = "info")]
public List<Info> Info { get; set; }
}
[DataContract(Name = "info", Namespace = "")]
public class Info
{
[DataMember(Name = "valueName")]
public string ValueName { get; set; }
[DataMember(Name = "value")]
public string Value { get; set; }
}
However, when I try with the following:
var alert = new Alert()
{
Identifier = "SecretID",
Info = new List<Info>
{
new Info() {ValueName = "Name1", Value = "Info1"},
new Info() {ValueName = "Name2", Value = "Info2"},
}
}
I get:
<alert>
<identifier>SecretID</identifier>
<info>
<info xmlns="">
<valueName>Name1</valueName>
<value>Info1</value>
</info>
<info xmlns="">
<valueName>Name2</valueName>
<value>Info2</value>
</info>
</info>
</alert>
I don't need the extra <info> tag, and the namespace xmlns="" would be nice to have removed too. What should I do to get rid of it?
You can use dictionary or key value pairs as mentioned below:
[DataContract(Name = "alert", Namespace = "")]
public class Alert
{
[DataMember(Name = "identifier")]
public string identifier { get; set; }
[DataMember(Name = "info")]
public KeyValuePair<string, string> Info { get; set; }
}
var alert = new Alert()
{
Identifier = "SecretID",
Info = new KeyValuePair<string, string>()
}

Serialize object to specific format, remove namespaces and move attribute

I'm trying to build serialization for my application that must export data in specific format, below is sample what is expected:
<?xml version="1.0" encoding="utf-8"?>
<sync>
<table name="Test" diff="0" mode="db">
<keys>
<key>MY_NUMBER</key>
<key>ID</key>
</keys>
<items task="modify">
<item ID="OK" MY_NUMBER="two"/>
<item ID="NT" MY_NUMBER="two"/>
</items>
</table>
<table name="Second" diff="1" mode="x">
<keys>
<key>ID</key>
</keys>
<items task="add">
<item ID="x" TYPE="c"/>
</items>
</table>
</sync>
I was able to get similar results:
<?xml version="1.0" encoding="utf-8"?>
<sync>
<table name="Test" diff="0" mode="db" task="modify">
<keys>
<key>MY_NUMBER</key>
<key>ID</key>
</keys>
<items>
<item d4p1:type="FirstItem" ID="OK" MY_NUMBER="two" xmlns:d4p1="http://www.w3.org/2001/XMLSchema-instance" />
<item d4p1:type="FirstItem" ID="NT" MY_NUMBER="two" xmlns:d4p1="http://www.w3.org/2001/XMLSchema-instance" />
</items>
</table>
<table name="SecondTest" diff="1" mode="x" task="add">
<keys>
<key>ID</key>
</keys>
<items>
<item d4p1:type="SecondItem" ID="x" TYPE="c" xmlns:d4p1="http://www.w3.org/2001/XMLSchema-instance" />
</items>
</table>
</sync>
But I get unwanted namespaces, I've tried searching SO for solutions (Omitting all xsi and xsd namespaces when serializing an object in .NET?, Remove Namespaces During XML Serialization) but without luck.
I have my classes defined like this:
namespace Sync.Models
{
[XmlRoot("sync")]
[XmlInclude(typeof(FirstItem))]
[XmlInclude(typeof(SecondItem))]
public class Export
{
[XmlElement(ElementName = "table")]
public Table users { get; set; }
[XmlElement(ElementName = "table2")]
public Table items { get; set; }
}
public class Table
{
[XmlAttribute("name")]
public string name { get; set; }
[XmlAttribute("diff")]
public int diff { get; set; }
[XmlAttribute("mode")]
public string mode { get; set; }
[XmlArray("keys")]
[XmlArrayItem("key")]
public List<string> Keys { get; set; }
[XmlArray("items")]
[XmlArrayItem("item")]
public List<BaseItem> Items { get; set; }
[XmlAttribute("task")]
public string Task { get; set; }
}
public class FirstItem:BaseItem
{
[XmlAttribute("MY_NUMBER")]
public string Number { get; set; }
}
public class SecondItem:BaseItem
{
[XmlAttribute("TYPE")]
public string Type { get; set; }
}
}
And finally my serialization functionality:
var testData = new Export
{
users = new Table
{
name = "Test",
diff = 0,
mode = "db",
Keys = new List<string> { "MY_NUMBER", "ID" },
Items = new List<BaseItem>
{
new FirstItem {Id = "OK", Number = "two"},
new FirstItem {Id = "NT", Number = "two"}
},
Task = "modify"
},
items = new Table
{
name = "SecondTest",
diff = 1,
mode = "x",
Keys = new List<string> { "ID" },
Items = new List<BaseItem>
{
new SecondItem{Id = "x",Type = "c"}
},
Task = "add"
}
};
var fileName_tmp = String.Format(#"{0}\xml1.xml", Application.StartupPath);
var fileName = String.Format(#"{0}\xml.xml", Application.StartupPath);
var serializer = new XmlSerializer(typeof(Export));
using (TextWriter writer = new StreamWriter(fileName_tmp))
{
serializer.Serialize(writer, testData, new XmlSerializerNamespaces(new[] {XmlQualifiedName.Empty}));
}
using (FileStream inputStream = File.OpenRead(fileName_tmp))
{
using (StreamReader inputReader = new StreamReader(inputStream))
{
using (StreamWriter outputWriter = File.CreateText(fileName))
{
string tempLineValue;
while (null != (tempLineValue = inputReader.ReadLine()))
{
outputWriter.WriteLine(tempLineValue.Replace("table2", "table"));
}
}
}
}
1. I would like to remove unwanted namespaces and type attribute from nodes, but as I wrote before solution I found isn't working.
2. I need to have multiple nodes with same name (table), for now my only solution is to replace tag after serialization. I know I could use List to store tables, but during serialization this is giving me one extra unwanted level-can this be removed? Or custom serialization is only option?
3. Right now Task property from table is stored as attribute of table node in xml. Can I move it to items, to get desired result? Or do I must create custom serialization?
you can remove namesapces by add this code
using (FileStream stream = new FileStream("FilePath",FileMode.Create))
{
XmlSerializer serializer = new XmlSerializer(typeof(YourClass));
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
ns.Add("", "");
serializer.Serialize(stream," Your Object to Serialize",ns);
}

Correct way to convert Xml to Objects?

I have very simple Xml structure that I want to convert to list of objects. My code does work but I think this is not the correct way of doing this and since I never did this I think there might be simpler way of doing what I want.
Xml example
<root>
<item>
<name>Item 1</name>
<price>30.00</price>
</item>
<item>
<name>Item 2</name>
<price>55.00</price>
</item>
</root>
Code to gather xml and create list of objects
class Program
{
static void Main(string[] args)
{
List<Item> itemList = new List<Item>();
var url = "http://xmlurl.com/xml";
// Load xml data
XmlDocument myXmlDocument = new XmlDocument();
myXmlDocument.Load(url);
// Select items and loop
var xmlItems = myXmlDocument.SelectNodes("/root/item");
foreach (XmlNode item in xmlItems)
{
var newItem = new Item();
foreach (XmlNode i in item)
{
// Since I cannot query them properly I need to check every item node
switch (i.Name)
{
case "name":
newItem.Name = i.InnerText;
break;
case "price":
newItem.Price = Convert.ToDecimal(i.InnerText);
break;
}
}
itemList.Add(newItem);
}
// Test it out
foreach (var item in itemList.OrderBy(x => x.Price))
{
Console.WriteLine(item.Name + " | " + item.Price);
}
Console.ReadLine();
}
}
class Item
{
public string Name { get; set; }
public decimal Price { get; set; }
}
Using LINQ:
XDocument xdoc = XDocument.Load("myXml.xml");
List<Item> items = (from item in xdoc.Descendants("item")
select new Item {
Name = item.Element("name").Value,
Price = item.Element("price").Value
}).ToList();
You should use XmlSerializer, example:
Classes:
[XmlType(TypeName="item")]
public class Item {
public string Name { get; set; }
public decimal Price { get; set; }
}
[XmlRoot(ElementName = "root")]
public class ItemList : List<Item> {
}
Getting them from markup:
const string test = #"<root>
<item>
<name>Item 1</name>
<price>30.00</price>
</item>
<item>
<name>Item 2</name>
<price>55.00</price>
</item>
</root>";
var serializer = new XmlSerializer(typeof(ItemList));
List<Item> result;
using (var reader = new StringReader(test)) {
result = (List<Item>)serializer.Deserialize(reader);
}
You can define your class:
[XmlType("item")]
public class Item
{
[XmlElement("name")]
public string Name { get; set; }
[XmlElement("price")]
public decimal Price { get; set; }
}
And then deserialize the Xml:
var xml = #"<root>
<item>
<name>Item 1</name>
<price>30.00</price>
</item>
<item>
<name>Item 2</name>
<price>55.00</price>
</item>
</root>";
List<Item> items;
var serializer = new XmlSerializer(typeof(List<Item>),
new XmlRootAttribute("root"));
using(var stream = new StringReader(xml))
{
items = (List<Item>)serializer.Deserialize(stream);
}
if(items != null)
{
foreach(var item in items)
{
Console.Write(item);
}
}

Categories

Resources