XML list not enclosed in root element deserialization - c#

My XML has structure similar to:
<rootNode>
<node/>
<otherNode/>
<specificNode>
nested nodes
</specificNode>
<specificNode>
nested nodes
</specificNode>
</rootNode>
then I have corresponding class:
class rootNode
{
string node;
string otherNode;
List<specificNodesClass> specificNodes;
}
class specificNodesClass
{
//all the specific Node's nested nodes
}
How can I deserialize the XML to fullfill rootNode type object?
I've tried :
XmlSerializer serializer = new XmlSerializer(typeof(rootNode));
result = (rootNode)serializer.Deserialize(xdocument.CreateReader(ReaderOptions.None));
with [XmlElement("specificNode")] above the List<specificNodesClass> specificNodes;, but I get "Input string was not in a correct format." exception.
Could it be an exception caused by specificNode's nested elements incorrect deserialization?
Problem was at one of the specificNode's nested nodes, as I suspected. Problem solved! Thank you everybody!

You can use following code to deserialize the XML:
XmlSerializer deserializer = new XmlSerializer(typeof(rootNode));
TextReader reader = new StreamReader(#"D:\myXml.xml");//path of xml file
object obj = deserializer.Deserialize(reader);
rootNode XmlData = (rootNode)obj;
reader.Close();
For more freferences, Click here

Decorate class rootNode with [XmlRoot("rootNode")] and decorate the properties of your class appropriately with [XmlElement()]
You could also use
public static T DeSerializeObject<T>(string xml)
{
if (string.IsNullOrEmpty(xml))
{
return default(T);
}
XmlSerializer _xs = new XmlSerializer(typeof(T));
using (StringReader _tr = new StringReader(xml))
{
using (XmlReader _xr = XmlReader.Create(_tr, new XmlReaderSettings()))
{
return (T)_xs.Deserialize(_xr);
}
}
}

Related

Deserializing XML Array in unity

Im trying to deserialize an array of objects from a XML Document.
The document built in the following structure:
<?xml version="1.0" encoding="UTF-8"?>
<root>
<element>
.....
</element>
<element>
.....
</element>
</root>
But for some reason Im having lots of problems doing so.
This is my function which I call to deserialize it:
public static CardModel[] Load(string text)
{
XmlRootAttribute xRoot = new XmlRootAttribute();
xRoot.ElementName = "root";
xRoot.IsNullable = true;
XmlSerializer serializer = new XmlSerializer(typeof(CardModel[]),xRoot);
StringReader reader = new StringReader(text);
CardModel[] o = serializer.Deserialize(reader) as CardModel[];
reader.Close();
return o;
}
And I am not sure if its done correctly or not. Because I know that in json you are unable to deserialize an array and you have to do some sort of "hack".
In the CardModel class (which is the element of the array) i use above the class the tag [XmlRoot("root")]. I have also tried to use [XmlRoot("element")] but still im getting stuck.
Afaik you can't directly deserialize into an array but would need a wrapper class like
[Serializable]
[XMLRoot("root")]
public class Root
{
// This does the magic of treating all "element" items nested under the root
// As part of this array
[XmlArray("element")]
public CardModel[] models;
}
And rather deserilialize into that like
public static CardModel[] Load(string text)
{
// I don't think that you need the attribute overwrite here
var serializer = new XmlSerializer(typeof(Root));
using(var reader = new StringReader(text))
{
var root = (Root) serializer.Deserialize(reader);
return root.models;
}
}

Deserialize object property with StringReader vs XmlNodeReader

Why does XmlSerializer populate my object property with an XmlNode array when deserializing an empty typed element using XmlNodeReader instead of an empty string like it does when using StringReader (or XmlTextReader)?
The second assertion in the following code sample fails:
var doc = new XmlDocument();
doc.Load(new StringReader(#"
<Test xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance""
xmlns:xsd=""http://www.w3.org/2001/XMLSchema"">
<Value xsi:type=""xsd:string"" />
</Test>"));
var ser = new XmlSerializer(typeof (Test));
var reader1 = new StringReader(doc.InnerXml);
var obj1 = (Test) ser.Deserialize(reader1);
Debug.Assert(obj1.Value is string);
var reader2 = new XmlNodeReader(doc.FirstChild);
var obj2 = (Test) ser.Deserialize(reader2);
Debug.Assert(obj2.Value is string);
public class Test
{
public object Value { get; set; }
}
I'm guessing it has something to do with the null internal NamespaceManager property but I'm not sure how to work around this mysterious limitation. How can I reliably deserialize a subset of my parsed XML document without converting it back into a string and re-parsing?
It looks like this is a very old XmlNodeReader bug that Microsoft have no intention of fixing. (Archived Microsoft Connect link here). I found a workaround on Lev Gimelfarb's blog here that adds namespaces to the reader's NameTable as prefixes are looked up.
public class ProperXmlNodeReader : XmlNodeReader
{
public ProperXmlNodeReader(XmlNode node) : base(node)
{
}
public override string LookupNamespace(string prefix)
{
return NameTable.Add(base.LookupNamespace(prefix));
}
}

How to display a large XML file (>21MB) in a tree view quickly

I need to display a large XML file (>21MB) in a tree view control in a C# Windows Form application. I have written the code which is working for small XML files but when i am trying to open a BIG XML file (>1 MB), its taking too much of time.
Can anyone suggest how i can optimise this and suggest me any changes or alternatives to achieve this.
Below is the code snippet:
private void CreateTreeViewFromATXML(string strSrcFileName)
{
XmlDataDocument xmldoc = new XmlDataDocument();
XmlNode xmlnode ;
FileStream fs = new FileStream(strSrcFileName, FileMode.Open, FileAccess.Read);
xmldoc.Load(fs);
xmlnode = xmldoc.ChildNodes[1];
XMLTreeView.Nodes.Clear();
XMLTreeView.Nodes.Add(new TreeNode(xmldoc.DocumentElement.Name));
TreeNode tNode ;
tNode = XMLTreeView.Nodes[0];
AddNode(xmlnode, tNode);
}
private void AddNode(XmlNode inXmlNode, TreeNode inTreeNode)
{
//XmlNode xNode ;
TreeNode tNode ;
XmlNodeList nodeList ;
int i = 0;
if (inXmlNode.HasChildNodes)
{
nodeList = inXmlNode.ChildNodes;
foreach (XmlNode XNode in inXmlNode.ChildNodes)
{
tNode = new TreeNode(XNode.Name);
inTreeNode.Nodes.Add(tNode);
AddNode(XNode, tNode);
}
}
else
{
inTreeNode.Text = inXmlNode.InnerText.ToString();
}
}
I would wrap your code like this:
XMLTreeView.BeginUpdate();
try
{
CreateTreeViewFromATXML(strSrcFileName);
}
catch (Exception e)
{
//Handle any error
}
finally
{
XMLTreeView.EndUpdate();
}
If you're not in an update block it's repainting the GUI on every node add and that's expensive. You also have recursion in AddNode but if the XML isn't too deeply nested it shouldn't be an issue.
I would suggest using XDocument and XML to Linq for a faster parsing. You can use the following code to parse the XML:
using System.Xml;
using System.Xml.Linq;
using System.Data;
XDocument xdoc = XDocument.Load(XMLFile);
var item = from items in xdoc.Element("EPICORTLOG").Descendants("POS")
where (string)items.Element("Id") == strSelectedPOSID
select items.Elements("TRADE").Elements("ITEM").ToList().ToList();
You can then follow the explanation in the following link to parse the XML:
http://www.dotnetcurry.com/showarticle.aspx?ID=564
The article above will explain the XML to LINQ programming. Using the above method you can load XML files as big as 10MB in a short time.
Recently, I used TreeView component to implement my HTML editor in C#, I used serialized data structure to impove the performance to open and save a XML file.
From my experience , using this structure and serialize read and write file can open file up to 20M byes within 2 seconds in my computer. This solution can open a XML file over 2G bytes in my C# application. Hope this solution can help you better.
Example to define Serializable Structure for TreeView and TreeNode
[Serializable]
public class TreeViewData
{
public TreeNodeData[] Nodes;
public TreeViewData(){ }
public TreeViewData(TreeView treeview)
{
//your code
}
public TreeViewData(TreeNode treenode)
{
//your code
}
public void PopulateTree(TreeView treeview)
{
//your code
}
public void PopulateSubTree(TreeNode treenode)
{
//your code
}
}
[Serializable]
public class TreeNodeData
{
public string Text;
public int ImageIndex;
public int SelectedImageIndex;
public string Tag;
public TreeNodeData[] Nodes;
public TreeNodeData() {}
public TreeNodeData(TreeNode node)
{
// your code
}
public TreeNode ToTreeNode()
{
// your code
}
}
Example to serialize read XML file
System.Xml.Serialization.XmlSerializer ser = new System.Xml.Serialization.XmlSerializer(typeof(TreeViewData));
System.IO.FileStream file = new System.IO.FileStream(strFilename, FileMode.Open);
System.Xml.XmlTextReader reader = new System.Xml.XmlTextReader(file);
TreeViewData treeData = (TreeViewData)ser.Deserialize(reader);
treeData.PopulateTree(TreeView1);
Example to serialize write XML file
System.Xml.Serialization.XmlSerializer ser = new System.Xml.Serialization.XmlSerializer(typeof(TreeViewData));
System.IO.FileStream file = new System.IO.FileStream(strFilename, System.IO.FileMode.Create);
System.Xml.XmlTextWriter writer = new System.Xml.XmlTextWriter(file, null);
ser.Serialize(writer, new TreeViewData(TreeView1));

XmlSerializer - Encoding not supported

I have the following extension method to serialize my class....
public static string SerializeToXml<T>(this object obj)
{
XDocument doc = new XDocument();
XmlSerializer ser = new XmlSerializer(typeof(T));
using (var writer = doc.CreateWriter())
{
ser.Serialize(writer, obj);
}
return doc.ToString();
}
This seems to work fine and returns the following string for my serialized object:
<AuthenticatedUser xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Username>mark</Username>
<UserID>4</UserID>
<Roles>
<string>AuthenticatedUsers</string>
</Roles>
<IsValid>false</IsValid>
</AuthenticatedUser>
However when I try to deserialize this string using the method below I get this error:
{"The encoding style '<AuthenticatedUser xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\">\r\n <Username>mark</Username>\r\n <UserID>4</UserID>\r\n <Roles>\r\n <string>AuthenticatedUsers</string>\r\n </Roles>\r\n <IsMale>false</IsMale>\r\n</AuthenticatedUser>' is not valid for this call because this XmlSerializer instance does not support encoding. Use the SoapReflectionImporter to initialize an XmlSerializer that supports encoding."}
Method....
public static T DeserializeFromXml<T>(this string xml)
{
var element = XElement.Parse(xml);
XmlSerializer ser = new XmlSerializer(typeof(T));
using (var reader = element.CreateReader())
{
return (T)ser.Deserialize(reader, xml);
}
}
So after I read the error message I changed the deserialize method to use the SoadReflectionImporter....
public static T DeserializeFromXml<T>(this string xml)
{
var element = XElement.Parse(xml);
SoapReflectionImporter soap = new SoapReflectionImporter();
var mapping = soap.ImportTypeMapping(typeof(T));
XmlSerializer ser = new XmlSerializer(mapping);
using (var reader = element.CreateReader())
{
return (T)ser.Deserialize(reader, xml);
}
}
However I now get this error...
{"The encoding style '<AuthenticatedUser xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\">\r\n <Username>mark</Username>\r\n <UserID>4</UserID>\r\n <Roles>\r\n <string>AuthenticatedUsers</string>\r\n </Roles>\r\n <IsValid>false</IsValid>\r\n</AuthenticatedUser>' is not valid for this call. Valid values are 'http://schemas.xmlsoap.org/soap/encoding/' for SOAP 1.1 encoding or 'http://www.w3.org/2003/05/soap-encoding' for SOAP 1.2 encoding."}
Does anyone know where I'm going wrong and how I can deserialize this string successfully?
The problem is the overload of the Deserialize method that you are calling:
return (T)ser.Deserialize(reader, xml);
The xml parameter in the call specifies the encoding style, but in this case you are passing the xml from the serialization. Simply delete the second parameter and just call Deserialize with the reader and it should work fine:
return (T)ser.Deserialize(reader);
XElement.CreateReader() doesn't return the XDeclaration.
Instead, try making an XmlReader from a StringReader.
Why are you using XmlSerializer ?
Unless you must control the way the output XML looks, you should be using DataContractSerializer
Here is a nice blog post about the two
Do you need the Parse(xml) call and the reader element? Since you have the string, can't you just deserialize the string? First convert to bytes...
byte [] bytes = Encoding.Unicode.GetBytes(xml);
MemoryStream mem = new MemoryStream(bytes);
returnValue = (T)ser.Deserialize(mem);

How can I read information from an XML file and set them to attributes in a class?

I have this code:
public class Hero
{
XmlReader Reader = new XmlTextReader("InformationRepositories/HeroRepository/HeroInformation.xml");
XmlReaderSettings XMLSettings = new XmlReaderSettings();
public ImageSource GetHeroIcon(string Name)
{
XMLSettings.IgnoreWhitespace = true;
XMLSettings.IgnoreComments = true;
Reader.MoveToAttribute(" //I'm pretty much stuck here.
}
}
And this is the XML file I want to read from:
<?xml version="1.0" encoding="utf-8" ?>
<Hero>
<Legion>
<Andromeda>
<HeroType>Agility</HeroType>
<Damage>39-53</Damage>
<Armor>3.1</Armor>
<MoveSpeed>295</MoveSpeed>
<AttackType>Ranged(400)</AttackType>
<AttackRate>.75</AttackRate>
<Strength>16</Strength>
<Agility>27</Agility>
<Intelligence>15</Intelligence>
<Icon>Images/Hero/Andromeda.gif</Icon>
</Andromeda>
</Legion>
<Hellbourne>
</Hellbourne>
</Hero>
I'm tring to get the ,/Icon> element.
MoveToAttribute() won't help you, because everything in your XML is elements. The Icon element is a subelement of the Andromeda element.
One of the easiest ways of navigating an XML document if you're using the pre-3.5 xml handling is by using an XPathNavigator. See this example for getting started, but basically you just need to create it and call MoveToChild() or MoveToFollowing() and it'll get you to where you want to be in the document.
XmlDocument doc = new XmlDocument();
doc.Load("InformationRepositories/HeroRepository/HeroInformation.xml");
XPathNavigator nav = doc.CreateNavigator();
if (nav.MoveToFollowing("Icon",""))
Response.Write(nav.ValueAsInt);
Note that an XPathNavigator is a forward only mechanism, so it can be problematic if you need to do looping or seeking through the document.
If you're just reading XML to put the values into objects, you should seriously consider doing this automatically via object serialization to XML. This would give you a painless and automatic way to load your xml files back into objects.
Mark your attributes in your object according to the element you want to load them to:
See: http://msdn.microsoft.com/en-us/library/system.xml.serialization.xmlattributeattribute.aspx
If, for some reason, you can't do this to your current object, consider making a bridge object which mirrors your original object and add a AsOriginal() method which returns the Original Object.
Working off the msdn example:
public class GroupBridge
{
[XmlAttribute (Namespace = "http://www.cpandl.com")]
public string GroupName;
[XmlAttribute(DataType = "base64Binary")]
public Byte [] GroupNumber;
[XmlAttribute(DataType = "date", AttributeName = "CreationDate")]
public DateTime Today;
public Group AsOriginal()
{
Group g = new Group();
g.GroupName = this.GroupName;
g.GroupNumber = this.GroupNumber;
g.Today = this.Today;
return g;
}
}
public class Group
{
public string GroupName;
public Byte [] GroupNumber;
public DateTime Today;
}
To Serialize and DeSerialize from LINQ objects, you can use:
public static string SerializeLINQtoXML<T>(T linqObject)
{
// see http://msdn.microsoft.com/en-us/library/bb546184.aspx
DataContractSerializer dcs = new DataContractSerializer(linqObject.GetType());
StringBuilder sb = new StringBuilder();
XmlWriter writer = XmlWriter.Create(sb);
dcs.WriteObject(writer, linqObject);
writer.Close();
return sb.ToString();
}
public static T DeserializeLINQfromXML<T>(string input)
{
DataContractSerializer dcs = new DataContractSerializer(typeof(T));
TextReader treader = new StringReader(input);
XmlReader reader = XmlReader.Create(treader);
T linqObject = (T)dcs.ReadObject(reader, true);
reader.Close();
return linqObject;
}
I don't have any example code of Serialization from non-LINQ objects, but the MSDN link should point you in the right direction.
You can use linq to xml:
public class XmlTest
{
private XDocument _doc;
public XmlTest(string xml)
{
_doc = XDocument.Load(new StringReader(xml);
}
public string Icon { get { return GetValue("Icon"); } }
private string GetValue(string elementName)
{
return _doc.Descendants(elementName).FirstOrDefault().Value;
}
}
you can use this regular exspression "<Icon>.*</Icon>" to find all the icons
then just remove the remove the tag, and use it....
would be a lot shorter
Regex rgx = new Regex("<Icon>.*</Icon>");
MatchCollection matches = rgx.Matches(xml);
foreach (Match match in matches)
{
string s= match.Value;
s= s.Remove(0,6)
s= s.Remove(s.LastIndexOf("</Icon>"),7);
console.Writeline(s);
}

Categories