De-serialize XML files with varying XmlRoot element names - c#

I have a large number of XML files that I need to perform de-serialization on. These files have varying root names (over 250). I'm trying to pass the root attribute name through XmlSerializer before accessing the XML class to retrieve my data. Here is what I have but I'm still getting an error that the root name was expected although the XmlElement class is passing the attribute to the XmlSerializer class.
The method used to retrieve the file:
string strXmlDoc = path;
XmlDocument objXmlDoc = new XmlDocument();
objXmlDoc.Load(strXmlDoc);
XmlElement objRootElem = objXmlDoc.DocumentElement;
XmlSerializer xmlSerial = new XmlSerializer(typeof(XMLFile), new XmlRootAttribute(objRootElem.ToString()));
StreamReader sr = new StreamReader(path);
XMLFile entity = xmlSerial.Deserialize(sr) as XMLFile;
The XML classes file:
[Serializable]
//[XmlRoot("randomname")] Removed this line since I'm getting the XmlRoot attribute in the XmlSerializer line.
public class XMLFile
{
[System.Xml.Serialization.XmlElement("RECORD")]
public RECORD RECORD { get; set; }
}
[Serializable]
public class RECORD
{
[XmlElement("BK01")]
public Record Bk01 { get; set; }
[XmlElement("BK02")]
public Record Bk02 { get; set; }
}
[Serializable]
public class Record
{
[XmlAttribute("Value")]
public string Value { get; set; }
}

Change this:
XmlSerializer xmlSerial =
new XmlSerializer(typeof(XMLFile), new XmlRootAttribute(objRootElem.ToString()));
to this:
XmlSerializer xmlSerial =
new XmlSerializer(typeof(XMLFile), new XmlRootAttribute(objRootElem.Name));
^^^
XmlElement.ToString() will always return System.Xml.XmlElement, which is not what you want.

Related

Desearilizing Xml with multiple InnerText Nodes

I am having trouble with deserializing a XML into C# Model. I am pulling that XML from external API, so i have no control over it. It has multiple "InnerText" nodes, that serialized cant deserialize correctly(last one wins, orhers are lost).
I`ve already fixed this using XmlDocument Class, but i need to do it with model instead.
The XML i am trying to deserialize:
<root>
<passage>
<hlword>Test</hlword>
your Internet.....
<hlword>test</hlword>
from Ookla.
</passage>
</root>
C# Classes:
[XmlRoot(ElementName = "passage")]
public class Passage
{
[XmlElement(ElementName = "hlword")]
public List<string> Hlword { get; set; }
[XmlText]
public string InnerText { get; set; }
}
[XmlRoot(ElementName = "root")]
public class Root
{
[XmlElement(ElementName = "passage")]
public List<Passage> Passage { get; set; }
[XmlText]
public string InnerText { get; set; }
}
From example above, i need to extract: "Test your internet..... test from Ookla", Instead I am getting List of Passage class with 2 Hlwords (inner text "test") and inner text on Root class "from Ookla". All the text after elements is ommited.
Try reading the innertext using XmlDocument
var doc = new XmlDocument();
doc.LoadXml(xmlString);
var text = doc.SelectSingleNode("root/passage").InnerText;

C# object to xml serialization

I have json string which is deserialized into c# class object, now I am trying serialize it into xml and writing same to the xml file. It does not have any errors or exceptioins but unable to write on xml file. The class has array of objects
Below is my code:
This is class:
public class WorkspaceRootObject
{
public WorkspaceRootObject()
{
}
public string id { get; set; }
public string name { get; set; }
public string description { get; set; }
public string contextId { get; set; }
}
This is serialization:
//deserializing json
wso= JsonConvert.DeserializeObject <List<WorkspaceRootObject>>(finalResponse);
Console.WriteLine("after deserializing...");
FileStream fs = new FileStream("D:\\Rohit_VisualStudio\\ServerManagementFormRest\\bin\\Debug\\WorkSpaceDetails.xml", FileMode.OpenOrCreate);
//serializing into xml
XmlSerializer xs = new XmlSerializer(typeof(List<WorkspaceRootObject>), new System.Type[] {typeof(WorkspaceRootObject)});
TextWriter sw = new StreamWriter(fs);
xs.Serialize(sw, wso);
I have used Newtonsoft json. and after opening xml file it shows Invalid at the top level of the document. Error processing resource 'file:///D:/ProjectLocation/...

Deserialize xml to IList c#

I am trying to deserialize some xml into an IList, but I am having problems. This is what I have done so far:
The XML:
<?xml version="1.0" encoding="utf-8"?>
<Animals>
<Animal>
<Name>Cow</Name>
<Color>Brown</Color>
</Animal>
</Animals>
The Model:
[XmlRoot("Animals")]
public class Model
{
[XmlElement("Animal")]
public IList<Animal> AnimalList { get; set; }
}
public class Animal
{
[XmlElement("Name")]
public string Name{ get; set; }
[XmlElement("Color")]
public string Color{ get; set; }
}
Deserialization:
FileStream fs = new FileStream("file.xml", FileMode.Open);
XmlReader xml = XmlReader.Create(fs);
XmlSerializer ser = new XmlSerializer(typeof(List<Model>));
var list = (List<Model>)ser.Deserialize(xml);
I get an invalid operation exception when running the code above. What am I doing wrong?
Thanks,
James Ford
Try that:
// Create a new XmlSerializer instance with the type of the test class
XmlSerializer SerializerObj = new XmlSerializer(typeof(List<Model>));
// Create a new file stream for reading the XML file
FileStream ReadFileStream = new FileStream(#"C:\file.xml", FileMode.Open, FileAccess.Read, FileShare.Read);
// Load the object saved above by using the Deserialize function
List<Model> LoadedObj = (List<Model>)SerializerObj.Deserialize(ReadFileStream);
// Cleanup
ReadFileStream.Close();
The problem is that you are using an IList<Animal>. You need to use a List<Animal> so that it knows the specific type to use.
EDIT: Using the following code in LINQPad works perfectly. Only difference is I am loading the XML via string instead of file, but even when I change to a file it works fine. I just added the using for System.Xml.Serialization.
void Main()
{
string xml = #"<?xml version=""1.0"" encoding=""utf-8""?>
<Animals>
<Animal>
<Name>Cow</Name>
<Color>Brown</Color>
</Animal>
</Animals>";
XmlReader reader = XmlReader.Create(new StringReader(xml));
XmlSerializer ser = new XmlSerializer(typeof(Model));
var list = (Model)ser.Deserialize(reader);
list.Dump();
}
// Define other methods and classes here
[XmlRoot("Animals")]
public class Model
{
[XmlElement("Animal")]
public List<Animal> AnimalList { get; set; }
}
public class Animal
{
[XmlElement("Name")]
public string Name{ get; set; }
[XmlElement("Color")]
public string Color{ get; set; }
}
I think you need to change your XmlSerializer to this:
XmlSerializer ser = new XmlSerializer(typeof(Model));
Before you were trying to serialize a list of Models, you want to serialize a XML file into a Model, which contains a list of stuff.
Also, you need to change your ObjectList definition to
public List<Animal> AnimalList { get; set; }

Adding to XML file

I am making a WPF that searches through an XML file pulling out restaurant information. The XML is in this format:
<FoodPhoneNumbers>
<Restaurant Name="Pizza Place">
<Type>Pizza</Type>
<PhoneNumber>(123)-456-7890</PhoneNumber>
<Hours>
<Open>11:00am</Open>
<Close>11:00pm</Close>
</Hours>
</Restaurant>
</FoodPhoneNumbers>
I want to be able to add a new restaurant to the XML file. I have a textbox for the restaurant name, and type. Then three textboxes for the phone number. 4 comboboxes for the open hour, open minute, close hour, and close minute. I also have 2 listboxes for selecting AM or PM for the open and close times.
I assume I use XmlTextWriter, but I could not figure out how to add the text to a pre-existing XML file.
The simplest way isn't to use XmlTextWriter - it's just to load the whole into an in-memory representation, add the new element, then save. Obviously that's not terribly efficient for large files, but it's really simple if you can get away with it. For example, using XDocument:
XDocument doc = XDocument.Load("test.xml");
XElement restaurant = new XElement("Restaurant",
new XAttribute("Name", "Frenchies"),
new XElement("Type", "French"),
new XElement("PhoneNumber", "555-12345678"),
new XElement("Hours",
new XElement("Open", "1:00pm"),
new XElement("Close", "2:00pm")));
doc.Root.Add(restaurant);
doc.Save("test.xml");
Or, better:
XDocument doc = XDocument.Load("test.xml");
Restaurant restaurant = ...; // Populate a Restaurant object
// The Restaurant class could know how to serialize itself to an XElement
XElement element = restaurant.ToXElement();
doc.Root.Add(element);
The instance of XmlSerializer class can be used to achieve this.
[XmlRoot("FoodPhoneNumbers")]
public class FoodPhoneNumbers
{
[XmlElement(ElementName = "Restaurant")]
public List<Restaurant> Restaurants { get; set; }
}
public class Restaurant
{
[XmlAttribute]
public string Name { get; set; }
[XmlElement]
public string Type { get; set; }
[XmlElement]
public string PhoneNumber { get; set; }
[XmlElement(ElementName = "Hours")]
public List<Hours> Hours { get; set; }
}
public class Hours
{
[XmlElement]
public string Open { get; set; }
[XmlElement]
public string Close { get; set; }
}
Serialization/deserialization code:
// Deserialize.
FoodPhoneNumbers food;
using (Stream inputStream = File.OpenRead(inputFilePath))
food = (FoodPhoneNumbers) xmlSerializer.Deserialize(inputStream);
// Add a new one.
Restaurant restaurant = new Restaurant
{
Name = "Coffee restraurant",
PhoneNumber = "0xFF",
Type = "Coffee shop"
};
food.Restaurants.Add(restaurant);
// Serialize.
using (Stream outputStream = File.OpenWrite(outputFilePath))
xmlSerializer.Serialize(outputStream, food);

Inject XML attribute into serialization

I am trying to serialize an array and want to attach an attribute to the array. For example, the output I want is:
<ArrayOfThingie version="1.0">
<Thingie>
<name>one</name>
</Thingie>
<Thingie>
<name>two</name>
</Thingie>
</ArrayOfThingie>
This is just a primitive array, so I don't want to define the attribute for the array itself, just in its serialization. Is there a way to inject an attribute into the serialization?
You could create a wrapper for ArrayOfThingie just for serialization:
public class Thingie
{
[XmlElement("name")]
public string Name { get; set; }
}
[XmlRoot]
public class ArrayOfThingie
{
[XmlAttribute("version")]
public string Version { get; set; }
[XmlElement("Thingie")]
public Thingie[] Thingies { get; set; }
}
static void Main(string[] args)
{
Thingie[] thingies = new[] { new Thingie { Name = "one" }, new Thingie { Name = "two" } };
ArrayOfThingie at = new ArrayOfThingie { Thingies = thingies, Version = "1.0" };
XmlSerializer serializer = new XmlSerializer(typeof(ArrayOfThingie));
StringWriter writer = new StringWriter();
serializer.Serialize(writer, at);
Console.WriteLine(writer.ToString());
}
A bit of a hack would be to serialize the array to XML and then modify the serialized XML before saving. A cleaner way assuming the Array is a property of a class would be to Add an attribute to a serialized XML node.

Categories

Resources