XML DeSerialize - Possible to Trap Extra XML in File? - c#

Is there a way to trap the extra XML tags in a file that you did not anticipate in your class?
For Example:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml.Serialization;
namespace XmlDeserializerTest
{
class Program
{
static void Main(string[] args)
{
XmlSerializer deserializer = new XmlSerializer(typeof(PersonInfo));
StreamReader reader = new StreamReader(#"C:\XML\Xml.xml");
object obj = deserializer.Deserialize(reader);
PersonInfo D = (PersonInfo) obj;
Console.WriteLine(D.address.Age);
reader.Close();
Console.ReadLine();
}
}
[XmlRoot("MyInfo")]
public class PersonInfo
{
public string Name { get; set; }
public string Type { get; set; }
[XmlElement("Address")]
public Loc address = new Loc();
}
public class Loc
{
public string Age { get; set; }
public string Location { get; set; }
}
// File used by this program:
// <?xml version="1.0" encoding="utf-8"?>
// <MyInfo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
// <Address>
// <Age>51</Age>
// <Location>Tulsa</Location>
// <State>Oklahoma</State>
// </Address>
// <Name>Scott</Name>
// <Type>Programmer</Type>
//</MyInfo>
}
This does not produce an error, it just doesnt load the State information. It just ignores it. I was wondering if there was a way to Trap this or send the extra code to another class or something.
Thanks,
Scott

I believe you can use XmlSerializer's UnknownAttribute, UnknownElement, etc. events to trap such cases.

Related

Deserialize a single XML tag into separate properties with C#

Consider the following simplified XML. I get it passed from a service and don't have any influence on its structure. It contains 3 tags that are defined by their order, i.e. the first-occuring <string> always refers to the same property.
<?xml version="1.0" encoding="UTF-8"?>
<result>
<entry>
<string>foo</string>
<int>42</int>
<string>bar</string>
</entry>
<entry>
<string>baz</string>
<int>1234</int>
<string>foobar</string>
</entry>
</result>
I'd like to deserialize the <entry> elements into a class with separate properties, e.g.
public class ResultEntry {
// this property equals to the 1st-occuring <string> element in the XML
public String PropA { get; set; }
// this property equals to the 2nd-occuring <string> element in the XML
public String PropB { get; set; }
// this property equals to the <int> element in the XML
public Int32 PropC { get; set; }
}
Is there any way to deserialize the two <string> elements into the two different properties? I can't just add the [XmlElement(ElementName="string")] annotation to both of them, as this results an an InvalidOperationException.
One way could be to add a property like
[XmlElement(ElementName="string")]
public List<string> StringVals {get; set;}
instead, and to manually move the values later on, but this feels way too hacky to me.
Use following :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
namespace ConsoleApplication161
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
XmlReader reader = XmlReader.Create(FILENAME);
XmlSerializer serializer = new XmlSerializer(typeof(Result));
Result result = (Result)serializer.Deserialize(reader);
}
}
[XmlRoot("result")]
public class Result
{
[XmlElement("entry")]
public List<ResultEntry> entries { get; set; }
}
public class ResultEntry
{
[XmlElement("string")]
public List<String> PropA { get; set; }
[XmlElement("int")]
public int PropB { get; set; }
}
}
You could do something like below which I do not recommend
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
namespace ConsoleApplication161
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
XmlReader reader = XmlReader.Create(FILENAME);
XmlSerializer serializer = new XmlSerializer(typeof(Result));
Result result = (Result)serializer.Deserialize(reader);
}
}
[XmlRoot("result")]
public class Result
{
[XmlElement("entry")]
public List<ResultEntry> entries { get; set; }
}
public class ResultEntry
{
private string PropA { get; set; }
private string PropB { get; set; }
[XmlElement("string")]
public List<String> Properties {
get { return new List<string> { PropA, PropB};}
set { PropA = value[0]; PropB = value[1]; }
}
[XmlElement("int")]
public int PropC { get; set; }
}
}

Serialize XML array, attribute to Object

How Can I define an object to deserialize the following XML:
<body>
<S1 A="1">
<S2 B="1">
<S3 C="1"/>
<S3 C="1"/>
</S2>
<S2 B="2"/>
</S1>
<S1 A="2"/>
I'd strongly recommend to use xsd.exe, which can help in generating XML schema or common language runtime classes from XDR, XML, and XSD files, or from classes in a runtime assembly.
Open VS Developer Command Prompt
Type xsd.exe PathToXmlFile.xml /outputdir:OutputDir and press Enter - this will generate *.xsd file
Type xsd.exe PreviouslyCreatedXsdFile.xsd /classes /outputdir:OutputDir and press Enter - this will generate *.cs file (class definition).
That's all!
Try!
Try this....
Usings.....
using System;
using System.Xml.Serialization;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Xml;
Classes.....
[XmlRoot(ElementName = "S3")]
public class S3
{
[XmlAttribute(AttributeName = "C")]
public string C { get; set; }
}
[XmlRoot(ElementName = "S2")]
public class S2
{
[XmlElement(ElementName = "S3")]
public List<S3> S3 { get; set; }
[XmlAttribute(AttributeName = "B")]
public string B { get; set; }
}
[XmlRoot(ElementName = "S1")]
public class S1
{
[XmlElement(ElementName = "S2")]
public List<S2> S2 { get; set; }
[XmlAttribute(AttributeName = "A")]
public string A { get; set; }
}
[XmlRoot(ElementName = "body")]
public class Body
{
[XmlElement(ElementName = "S1")]
public List<S1> S1 { get; set; }
}
Code.....
string strXML = File.ReadAllText("xml.xml");
byte[] bufXML = ASCIIEncoding.UTF8.GetBytes(strXML);
MemoryStream ms1 = new MemoryStream(bufXML);
// Deserialize to object
XmlSerializer serializer = new XmlSerializer(typeof(Body));
try
{
using (XmlReader reader = new XmlTextReader(ms1))
{
Body deserializedXML = (Body)serializer.Deserialize(reader);
}// put a break point here and mouse-over deserializedXML….
}
catch (Exception ex)
{
throw;
}
Your XML.....
<body>
<S1 A="1">
<S2 B="1">
<S3 C="1"/>
<S3 C="1"/>
</S2>
<S2 B="2"/>
</S1>
<S1 A="2"/>
</body>
I added the end tag..... I am reading your XML in to a string from a file in the application build folder called xml.xml... you will need to get the XML string from somewhere else or create the xml.xml file and save your XML for the code above to work

Reading XML files with repeating structures using C#

I've got an XML file which describes connections, i.e.
<?xml version="1.0" encoding="utf-8"?>
<connections>
<connection name="Local server remote">
<ip>192.168.0.7 </ip>
<port>23 </port>
<description>
Remote controlling of that nice & neat box under the table.
</description>
</connection>
<connection name="Far, far away server HTTP access">
<ip>77.32.57.144 </ip>
<port>8080 </port>
<description>
A legend tells of a far, far away country of Russia, and of a server somewhere inside this mysterious country.
</description>
</connection>
</connections>
Is there an easy way to parse that XML file into an object of a class like:
class Connection {
public string Name;
public string IP;
public int Port;
public string Description;
}
?
You could use Linq to XML to read this in:
var xmlDoc = XDocument.Load("XMLFile1.xml");
if(xmlDoc.Root != null)
{
var connections = (xmlDoc.Root.Elements("connection").Select(e => new Connection
{
Description = (string) e.Element("description"),
IP = (string) e.Element("ip"),
Name = (string) e.Element("name"),
Port = (int) e.Element("port")
})).ToList();
}
Probably worth pointing out that your XML file contains an & character which will throw off the XML document load. I was able to run the above code by replacing the ampersand with &
You will have to create a wrapper type to contain the list of connections as it doesn't know what <connections> is, then the rest is taken care of by adding an XmlElement name to each field.
public static void Main(string[] args)
{
var serializer = new XmlSerializer(typeof (ConnectionList));
var connections = ((ConnectionList)serializer.Deserialize(new StreamReader("data.xml"))).Connections;
foreach (var connection in connections)
{
Console.WriteLine(connection.IP);
}
Console.ReadLine();
}
[XmlRoot("connections")]
public class ConnectionList
{
[XmlElement("connection")]
public List<Connection> Connections { get; set; } = new List<Connection>();
}
[XmlType("connection")]
public class Connection
{
[XmlElement("description")] public string Description;
[XmlElement("ip")] public string IP;
[XmlElement("name")] public string Name;
[XmlElement("port")] public int Port;
}
Note: '&' in the XML is an invalid character and must be escaped as &
Try this. Best method
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication1
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
XDocument doc = XDocument.Load(FILENAME);
List<Connection> connections = doc.Descendants("connection").Select(x => new Connection(){
Name = x.Attribute("name").Value,
IP = x.Element("ip").Value,
Port = int.Parse(x.Element("port").Value),
Description = x.Element("description").Value,
}).ToList();
}
}
public class Connection
{
public string Name { get; set; }
public string IP { get; set; }
public int Port { get; set; }
public string Description { get; set; }
}
}
​

there is an error in xml document (2 2) xmlns='' was not expected

The error I am getting is all over stackoverflow answered again and again, I have tried few changes in the code but not able to remove the error. here is the class I am using for serialization and deserialization. Please have a look at it.
I don't understand terms like XMLroot, XML element and namespace. So please answer accordingly, like what namespace should I give, what could be the XML root.
If u can edit it, it would be great:
namespace tudumo9
{
public class data
{
public string project_name;
public string note_text;
public string tag_text;
public DateTime start_date;
public DateTime due_date;
public string action;
public data(){}
}
}
My XML:
<?xml version="1.0"?>
<ArrayOfData xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<data>
<project_name>p1</project_name>
<tag_text>tagged</tag_text>
<start_date>0001-01-01T00:00:00</start_date>
<due_date>0001-01-01T00:00:00</due_date>
<action>Action</action>
</data>
</ArrayOfData>
Try this
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Xml;
using System.Xml.Serialization;
namespace ConsoleApplication25
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
XmlSerializer xs = new XmlSerializer(typeof(ArrayOfData));
XmlTextReader reader = new XmlTextReader(FILENAME);
ArrayOfData newArrayOfData = (ArrayOfData)xs.Deserialize(reader);
}
}
[XmlRoot("ArrayOfData")]
public class ArrayOfData
{
[XmlElement("data")]
public List<data> c_Data { get; set; }
}
[XmlRoot("data")]
public class data
{
[XmlElement("project_name")]
public string project_name { get; set; }
[XmlElement("note_text")]
public string note_text { get; set; }
[XmlElement("tag_text")]
public string tag_text { get; set; }
[XmlElement("start_date")]
public DateTime start_date { get; set; }
[XmlElement("due_date")]
public DateTime due_date { get; set; }
[XmlElement("action")]
public string action { get; set; }
}
}

Serialize a C# class to XML with attributes and a single value for the class

I am using C# and XmlSerializer to serialize the following class:
public class Title
{
[XmlAttribute("id")]
public int Id { get; set; }
public string Value { get; set; }
}
I would like this to serialize to the following XML format:
<Title id="123">Some Title Value</Title>
In other words, I would like the Value property to be the value of the Title element in the XML file. I can't seem to find any way to do this without implementing my own XML serializer, which I would like to avoid. Any help would be appreciated.
Try using [XmlText]:
public class Title
{
[XmlAttribute("id")]
public int Id { get; set; }
[XmlText]
public string Value { get; set; }
}
Here's what I get (but I didn't spend a lot of time tweaking the XmlWriter, so you get a bunch of noise in the way of namespaces, etc.:
<?xml version="1.0" encoding="utf-16"?>
<Title xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
id="123"
>Grand Poobah</Title>
XmlTextAttribute probably?
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; }
}
}

Categories

Resources