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
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");
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
}
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>()
}
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);
}
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);
}
}