XmlSerializer access child logical elements in parent element - c#

I am using the standard .NET XmlSerializer to deserialize the following xml:
<root>
<Element>
<Grouping1>
<Item1>First</Item1>
<Item2>Second</Item2>
</Grouping1>
<Grouping2>
<Item3>Third</Item3>
</Grouping2>
</Element>
</root>
I would like to serialize it into the following class:
class Element
{
[XmlElement("Item1")]
public string Item1 { get; set; }
[XmlElement("Item2")]
public string Item2 { get; set; }
[XmlElement("Item3")]
public string Item3 { get; set; }
}
Which of course doesn't work, because - for instance - <Item1> isn't located in <Element> but in the logical container <Grouping1>.
The question:
Is there a way of telling the XmlSerializer to look for the Item1 in the <Grouping1> element?
Something downs the lines of [XmlElement("Grouping1.Item1")]
PS: I don't want to create a Grouping1 class (as suggested here) because the groupings are only logical containers and shouldn't have their own class.

Using Xml Linq. A custom serializer would be much more complicated
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication4
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
XDocument doc = XDocument.Load(FILENAME);
List<Element> elements = doc.Descendants("Element").Select(x => new Element()
{
Item1 = (string)x.Descendants("Item1").FirstOrDefault(),
Item2 = (string)x.Descendants("Item2").FirstOrDefault(),
Item3 = (string)x.Descendants("Item3").FirstOrDefault()
}).ToList();
}
}
class Element
{
public string Item1 { get; set; }
public string Item2 { get; set; }
public string Item3 { get; set; }
}
}
Here is what serializer would look like
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using System.Xml.Serialization;
using System.Xml.Schema;
namespace ConsoleApplication4
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
XmlReader reader = XmlReader.Create(FILENAME);
XmlSerializer serializer = new XmlSerializer(typeof(Root));
Root root = (Root)serializer.Deserialize(reader);
}
}
[XmlRoot("root")]
public class Root
{
[XmlElement("Element")]
public List<Element> Element { get; set; }
}
public class Element : IXmlSerializable
{
private string Item1 { get; set; }
private string Item2 { get; set; }
private string Item3 { get; set; }
public void WriteXml(XmlWriter writer)
{
XElement element = new XElement("Element", new object[] {
new XElement("Grouping1", new object[] {
new XElement("Item1", Item1),
new XElement("Item2", Item2)
}),
new XElement("Grouping2", new XElement("Item3", Item3))
});
element.WriteTo(writer);
}
public void ReadXml(XmlReader reader)
{
XElement element = (XElement)XElement.ReadFrom(reader);
Item1 = (string)element.Descendants("Item1").FirstOrDefault();
Item2 = (string)element.Descendants("Item2").FirstOrDefault();
Item3 = (string)element.Descendants("Item3").FirstOrDefault();
}
public XmlSchema GetSchema()
{
return (null);
}
}
}

I don't want to create a Grouping1 class...
Not sure whether that's possible using serialization without creating the objects that output this XML.
An alternative to serialization is using the XmlReader to extract the properties in question (Item1, Item2, and Item3) and create a list of Element type, and XmlWriter to generate the whole XML file. Both classes provide fast, non-cached, and forward-only way to read and write XML files.
Assuming your XML file has multiple Element entries like:
<root>
<Element>
<Grouping1>
<Item1>First1</Item1>
<Item2>Second1</Item2>
</Grouping1>
<Grouping2>
<Item3>Third1</Item3>
</Grouping2>
</Element>
<Element>
<Grouping1>
<Item1>First2</Item1>
<Item2>Second2</Item2>
</Grouping1>
<Grouping2>
<Item3>Third2</Item3>
</Grouping2>
</Element>
</root>
... and a class named Element:
//The serializable attribute is not required here...
public class Element
{
public Element() { }
public string Item1 { get; set; }
public string Item2 { get; set; }
public string Item3 { get; set; }
public override string ToString() => $"{Item1}, {Item2}, {Item3}";
}
Create a function to read the file, create and return a list of Element items:
public List<Element> ReadElements(string xmlFile)
{
var elements = new List<Element>();
Element ele = null;
using (var xr = XmlReader.Create(xmlFile))
while (xr.Read())
{
if (xr.NodeType == XmlNodeType.Element)
{
if (xr.Name == "Element")
ele = new Element();
else if (xr.Name == "Item1")
{
xr.Read();
ele.Item1 = xr.Value;
}
else if (xr.Name == "Item2")
{
xr.Read();
ele.Item2 = xr.Value;
}
else if (xr.Name == "Item3")
{
xr.Read();
ele.Item3 = xr.Value;
}
}
else if (xr.NodeType == XmlNodeType.EndElement)
if (xr.Name == "Element")
elements.Add(ele);
}
return elements;
}
... and a method to write:
public void WriteElements(string xmlFile, IEnumerable<Element> elements)
{
var xmlSet = new XmlWriterSettings
{
Indent = true,
NewLineOnAttributes = true,
WriteEndDocumentOnClose = true,
};
using (var xr = XmlWriter.Create(xmlFile, xmlSet))
{
xr.WriteStartElement("root");
foreach(var ele in elements)
{
xr.WriteStartElement("Element");
xr.WriteStartElement("Grouping1");
xr.WriteStartElement("Item1");
xr.WriteString(ele.Item1);
xr.WriteEndElement();
xr.WriteStartElement("Item2");
xr.WriteString(ele.Item2);
xr.WriteEndElement();
xr.WriteEndElement();
xr.WriteStartElement("Grouping2");
xr.WriteStartElement("Item3");
xr.WriteString(ele.Item3);
xr.WriteEndElement();
xr.WriteEndElement();
xr.WriteEndElement();
}
}
}
A test to read and write the file like:
private void TheCaller()
{
var xmlFile = "XmlFile.xml";
var elements = ReadElements(xmlFile);
elements.ForEach(x => Console.WriteLine(x));
//...
WriteElements(xmlFile, elements);
}
Prints in my output window:
First1, Second1, Third1
First2, Second2, Third2

Related

C# XML Serialization having elements side-by-side

I am currently trying to understand the concept of serializing objects to XML with C#. I already got to a point where everything is working fine, but now I got the task to format the XML Output file in such a way, where the elements are side-by-side instead of underneath each other. For example:
This is how it needs to look like
<House>
<Address>
<Street>Some Street</Street><HouseNo>123</HouseNo><State>Texas</State>
</Address>
<House>
But I only manage to get it to look like this:
<House>
<Address>
<Street>Some Street</Street>
<HouseNo>123</HouseNo>
<State>Texas</State>
</Address>
</House>
Is there any way to format the output the way I described in the first example? Any help would be much appreciated.
I already tried to change some XmlWriterSettings, like Indent or NewLineHandling but none have worked so far. I also tried to read the XmlSerializer Code to try and understand what is happening or where to make changes to get to the result I want but that didn't seem to go all well.
You could crate an address class with custom serialization, here is a full working example,
using System;
using System.Diagnostics;
using System.IO;
using System.Xml;
using System.Xml.Linq;
using System.Xml.Schema;
using System.Xml.Serialization;
public class Program
{
public static void Main()
{
var houseBefore = new House
{
Address = new FlatAddress
{
Street = "SomeStreet",
HouseNo = "123",
State = "Texas"
}
};
var serializer = new XmlSerializer(typeof(House));
string xml;
using (var writer = new StringWriter())
{
serializer.Serialize(writer, houseBefore);
xml = writer.ToString();
}
Console.WriteLine(xml);
House houseAfter;
using (var reader = new StringReader(xml))
{
houseAfter = serializer.Deserialize(reader) as House;
}
Debug.Assert(houseBefore.Address.Street == houseAfter.Address.Street);
Debug.Assert(houseBefore.Address.HouseNo == houseAfter.Address.HouseNo);
Debug.Assert(houseBefore.Address.State == houseAfter.Address.State);
}
}
public sealed class House
{
public FlatAddress Address { get; set; }
}
public sealed class FlatAddress : IXmlSerializable
{
public string Street { set; get; }
public string HouseNo { set; get; }
public string State { set; get; }
public XmlSchema GetSchema()
{
return default;
}
public void ReadXml(XmlReader reader)
{
while (reader.Read())
{
if (reader.NodeType == XmlNodeType.Element)
{
switch (reader.Name)
{
case nameof(Street):
this.Street = reader.ReadElementContentAsString();
break;
case nameof(HouseNo):
this.HouseNo = reader.ReadElementContentAsString();
break;
case nameof(State):
this.State = reader.ReadElementContentAsString();
break;
}
}
}
}
public void WriteXml(XmlWriter writer)
{
writer.WriteElementString(nameof(Street), this.Street);
var houseNoXml = new XElement(nameof(HouseNo), this.HouseNo);
writer.WriteRaw(houseNoXml.ToString());
var stateXml = new XElement(nameof(State), this.State);
writer.WriteRaw(stateXml.ToString());
if (writer.Settings.NewLineHandling == NewLineHandling.Replace)
{
writer.WriteRaw(writer.Settings.NewLineChars);
}
if (writer.Settings.Indent)
{
writer.WriteRaw(writer.Settings.IndentChars);
}
}
}

Linq to XML complete Child Element XL structure

I'm trying to not use the old way of reading xml and give a try to linq to xml but I'm having a hard time to accomplish the following:
Response XML
<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body>
<PolicyResponse>
<serviceResponse>
<responseCode>0</responseCode>
<responseDescription>Success</responseDescription>
<responseDetail>Success</responseDetail>
<paging>
<pageNum>1</pageNum>
<pageSize>3</pageSize>
<totalRecords>3</totalRecords>
</paging>
</serviceResponse>
<detailsResponseList>
<detailResponse>
<policy>
<policySummaryInfo>
<PolicyNumber>1199128</PolicyNumber>
<PremiumChangeAmt>...</PremiumChangeAmt>
<WrittenAmt>...</WrittenAmt>
<PolicyStatusDesc>Expired</PolicyStatusDesc>
<BillingInfo>
<InsuredOrPrincipal>...</InsuredOrPrincipal>
</BillingInfo>
</policySummaryInfo>
</policy>
</detailResponse>
<detailResponse>
<policy>
<policySummaryInfo>
<PolicyNumber>1199128</PolicyNumber>
<PremiumChangeAmt>...</PremiumChangeAmt>
<WrittenAmt>...</WrittenAmt>
<PolicyStatusDesc>Active</PolicyStatusDesc>
<BillingInfo>
<InsuredOrPrincipal>...</InsuredOrPrincipal>
</BillingInfo>
</policySummaryInfo>
</policy>
</detailResponse>
</detailsResponseList>
</PolicyResponse>
</out2:getPolicySummaryResponse>
</soapenv:Body>
</soapenv:Envelope>
I'm doing this in C#
XDocument xdoc = new XDocument();
xdoc = XDocument.Parse(xmlResponse);
IEnumerable<XElement> items =
from el in xdoc.Descendants("detailResponse")
select el;
With this code I'm able to read bot detailReponse element but what I want is to keep only the XML detailResponse structure with the <PolicyStatusDesc></PolicyStatusDesc> equal to Active. Is that possible. I manage to gather specific data based on element names an so but how I can keep the whole XML child element structure (detailResponse element an its childs) by using Linq to XML.
Thanks
In your XML sample there in an invalid
</out2:getPolicySummaryResponse> tag which i have removed
Here is the code you may use for your result
IEnumerable<XElement> items =
from el in xdoc.Descendants("detailResponse")
where el.Element("policy")?.Element("policySummaryInfo")?.Element("PolicyStatusDesc")?.Value == "Active"
select el;
I often use code like below which gives a flatter results than using Serialization:
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);
XElement xPolicyResponse = doc.Descendants("PolicyResponse").FirstOrDefault();
PolicyResponse policyResponse = new PolicyResponse(xPolicyResponse);
}
}
public class PolicyResponse
{
public ServiceResponse serviceResponse { get; set; }
public List<DetailResponse> detailResponse { get; set; }
public PolicyResponse() {}
public PolicyResponse(XElement element)
{
XElement xServiceResponse = element.Element("serviceResponse");
List<XElement> xdetailResponseList = element.Descendants("detailResponse").ToList();
serviceResponse = new ServiceResponse(xServiceResponse);
detailResponse = xdetailResponseList.Select(x => new DetailResponse(x)).ToList();
}
}
public class ServiceResponse
{
public int responseCode { get; set; }
public string responseDescription { get; set; }
public string responseDetail { get; set; }
public int pageNum { get; set; }
public int pageSize { get; set; }
public int totalRecords { get; set; }
public ServiceResponse() { }
public ServiceResponse(XElement element)
{
responseCode = (int)element.Element("responseCode");
responseDescription = (string)element.Element("responseDescription");
responseDetail = (string)element.Element("responseDetail");
pageNum = (int)element.Descendants("pageNum").FirstOrDefault();
pageSize = (int)element.Descendants("pageSize").FirstOrDefault();
totalRecords = (int)element.Descendants("totalRecords").FirstOrDefault();
}
}
public class DetailResponse
{
public string policyNumber { get; set; }
public string premiumChangeAmt { get; set; }
public string writtenAmt { get; set; }
public string policyStatusDesc { get; set; }
public string insuredOrPrincipal { get; set; }
public DetailResponse() { }
public DetailResponse(XElement element)
{
XElement xPolicySummaryInfo = element.Descendants("policySummaryInfo").FirstOrDefault();
policyNumber = (string)xPolicySummaryInfo.Element("PolicyNumber");
premiumChangeAmt = (string)xPolicySummaryInfo.Element("PremiumChangeAmt");
writtenAmt = (string)xPolicySummaryInfo.Element("WrittenAmt");
policyStatusDesc = (string)xPolicySummaryInfo.Element("PolicyStatusDesc");
insuredOrPrincipal = (string)xPolicySummaryInfo.Descendants("InsuredOrPrincipal").FirstOrDefault();
}
}
}
You can get the elements where <PolicyStatusDesc> has the value Active by filtering the <detailResponse> elements using el.Descendants("PolicyStatusDesc"), then selecting those elements having the value Active.
Using query syntax:
var items = from el in xdoc.Descendants("detailResponse")
where el.Descendants("PolicyStatusDesc").Any(p => p.Value == "Active")
select el;
Or using method syntax:
var items = xdoc.Descendants("detailResponse")
.Where(el => el.Descendants("PolicyStatusDesc")
.Any(p => p.Value == "Active"));

Deserialize XML document, keeping track of order

I am parsing an XML document using the XMLSerialization tool. The sample XML file consists of paragraphs (string) and tables, which are a complex XML type. Tables consist of a series of row, which consists of a series of entry (string)
I need to keep track of the position of each table, relative to each paragraph. Is there a way of catching the position of each table as it is being parsed by the XMLSerialization tool? Or do I need to use a construct like [XMLAnyElement] and parse each paragraph and table sequentially in order to track the table position? I would prefer to avoid that approach, because my real XML files have many levels that would need manual parsing. I have a feeling that I am missing something really obvious here, but I've been scouring SO and trying multiple approaches, but with no straightforward solution.
Here is my basic code:
using System.Xml;
using System.Xml.Serialization;
using System.IO;
namespace XMLDeserializeTest
{
class Program
{
static void Main(string[] args)
{
string file = Environment.CurrentDirectory + #"\test.xml";
test testClass = Deserialize(file);
}
static test Deserialize(string url)
{
XmlSerializer reader =
new XmlSerializer(typeof(test));
StreamReader stream = new StreamReader(url);
return reader.Deserialize(stream) as test;
}
}
public class test
{
[XmlElement("paragraph")]
public List<string> paragraphs { get; set; }
[XmlElement("table")]
public List<Table> tables { get; set; }
public test()
{
}
}
public class Table
{
[XmlElement("row")]
public List<Row> rows { get; set; }
public int nodeNumber { get; set; } // This is what needs to be tracked
public Table()
{
}
}
public class Row
{
[XmlElement("entry")]
public List<string> entries { get; set; }
public Row()
{
}
}
My sample XML:
<?xml version="1.0" encoding="utf-8" ?>
<test>
<paragraph>Here is some text.</paragraph>
<paragraph>Here is some more text. The table follows this paragraph.</paragraph>
<table>
<row>
<entry>1</entry>
<entry>2</entry>
<entry>3</entry>
</row>
<row>
<entry>4</entry>
<entry>5</entry>
<entry>6</entry>
</row>
</table>
<paragraph>This is the last paragraph. This comes after the table.</paragraph>
</test>
I came up with one solution, using XDocument, but it seems pretty clumsy:
XDocument Xdoc = XDocument.Load(file);
int numParagraphs = 0;
int tableNumber = 0;
foreach(XElement item in Xdoc.Root.Descendants())
{
if (item.Name.LocalName.Equals("paragraph"))
{
numParagraphs++;
}
else if (item.Name.LocalName.Equals("table"))
{
testClass.tables[tableNumber].nodeNumber = numParagraphs;
tableNumber++;
}
}
One option would just be to serialize the paragraph "index" of the table into your XML at the time of serialization. That way you wouldn't have to do anything custom.
However, to do what you are looking for with the XmlSerializer you could handle the deserialization yourself for certain element types using the UnknownElement event. Notice that the XmlElement attributes have been removed from the test class in order for the table and paragraph elements to be handled.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
using System.IO;
namespace XMLDeserializeTest
{
class Program
{
static int paragraphCount = 0;
static void Main(string[] args)
{
string file = Environment.CurrentDirectory + #"\test.xml";
paragraphCount = 0;
test testClass = Deserialize(file);
}
static test Deserialize(string url)
{
XmlSerializer serializer = new XmlSerializer(typeof(test));
serializer.UnknownElement += serializer_UnknownElement;
StreamReader stream = new StreamReader(url);
return serializer.Deserialize(stream) as test;
}
static void serializer_UnknownElement(object sender, XmlElementEventArgs e)
{
test t = (test)e.ObjectBeingDeserialized;
if (e.Element.Name == "table")
{
var s = new XmlSerializer(typeof(Table));
var sr = new StringReader(e.Element.OuterXml);
Table newTable = s.Deserialize(sr) as Table;
newTable.nodeNumber = paragraphCount;
t.tables.Add(newTable);
}
else if (e.Element.Name == "paragraph")
{
String paragraphText = e.Element.InnerText;
t.paragraphs.Add(paragraphText);
paragraphCount++;
}
}
}
public class test
{
public List<string> paragraphs { get; set; }
public List<Table> tables { get; set; }
public test()
{
}
}
[Serializable, XmlRoot("table")]
public class Table
{
[XmlElement("row")]
public List<Row> rows { get; set; }
public int nodeNumber { get; set; } // This is what needs to be tracked
public Table()
{
}
}
[Serializable, XmlRoot("row")]
public class Row
{
[XmlElement("entry")]
public List<string> entries { get; set; }
public Row()
{
}
}
}

How to get value inside XML tag?

I have the follow XML structure:
<Document>
<Sectors>
<Sector>
SectorName1
<Subsectors>
<Subsector>Subsector1</Subsector>
<Subsector>Subsector2</Subsector>
</Subsectors>
</Sector>
<Sector>
SectorName2
<Subsectors>
<Subsector>Subsector1</Subsector>
<Subsector>Subsector2</Subsector>
</Subsectors>
</Sector>
</Sectors>
</Document>
Also I have classes for deserialize:
public class MetaDataXML
{
public class SectorXML
{
[XmlArrayItem(ElementName = "Sector")]
string SectorName { get; set; }
[XmlArray]
[XmlArrayItem(ElementName = "Subsector")]
public List<string> Subsectors { get; set; }
}
public List<SectorXML> Sectors { get; set; }
}
And part of code which do deserialize:
var xRoot = new XmlRootAttribute { ElementName = "Document", IsNullable = true };
var reader = new XmlSerializer(typeof(MetaDataXML), xRoot);
var data = (MetaDataXML)reader.Deserialize(streamXML);
After deserialization I successfully get subsectors velues, but I didn't get values for SectorName. How I need to organize my structure of class that I'll get values "SectorName1" and "SectorName2" for my string SectorName property?
I found that that this case it's a "Mixed Content". How we can parse this text values?
Whilst I am not entirely sure what it is you're trying to achieve here, I've made a few modifications to your XML class and provided some sample code below that is able to retrieve all of the information about a sector, including its name and the name of all the subsectors inside it.
XML Class:
namespace DocumentXml
{
[XmlRoot("Document")]
public class Document
{
[XmlArray("Sectors")]
[XmlArrayItem("Sector")]
public Sector[] Sectors { get; set; }
}
[XmlRoot("Sector")]
public class Sector
{
[XmlAttribute("SectorName")]
public string SectorName { get; set; }
[XmlArray("Subsectors")]
[XmlArrayItem("Subsector")]
public string[] Subsectors { get; set; }
}
}
Main Program Class:
namespace DocumentXml
{
class Program
{
static void Main(string[] args)
{
var path = #"D:\sandbox\DocumentXml\DocumentXml\Sample.xml";
var serializer = new XmlSerializer(typeof(Document));
var document = serializer.Deserialize(File.OpenRead(path)) as Document;
var sectors = document.Sectors;
foreach (var s in sectors)
{
Console.WriteLine($"Sector Name: {s.SectorName}");
foreach (var ss in s.Subsectors)
{
Console.WriteLine($"Subsector Name: {ss}");
}
Console.WriteLine();
}
Console.ReadKey();
}
}
}
Sample XML:
<Document>
<Sectors>
<Sector SectorName="SectorName1">
<Subsectors>
<Subsector>Subsector1</Subsector>
<Subsector>Subsector2</Subsector>
</Subsectors>
</Sector>
<Sector SectorName="SectorName2">
<Subsectors>
<Subsector>Subsector1</Subsector>
<Subsector>Subsector2</Subsector>
</Subsectors>
</Sector>
</Sectors>
</Document>
Output:
EDIT
Since the XML structure cannot be changed, this new class will preserve the structure and also allow you to get the value in question. XmlText returns everything inside the value so a custom set had to be used to ensure that the whitespace was correctly trimmed from it.
[XmlRoot("Document")]
public class MetaDataXml
{
[XmlArray("Sectors")]
[XmlArrayItem("Sector")]
public Sector[] Sectors { get; set; }
}
[XmlRoot("Sector")]
public class Sector
{
[XmlIgnore]
private string _sectorName;
[XmlText]
public string SectorName
{
get
{
return _sectorName;
}
set
{
_sectorName = value.Trim();
}
}
[XmlArray]
[XmlArrayItem(ElementName = "Subsector")]
public List<string> Subsectors { get; set; }
}
Sample Program:
class Program
{
static void Main(string[] args)
{
var path = #"D:\sandbox\DocumentXml\DocumentXml\Sample.xml";
using (var stream = File.OpenRead(path))
{
var deserializer = new XmlSerializer(typeof(MetaDataXml));
var data = (MetaDataXml)deserializer.Deserialize(stream);
foreach (var s in data.Sectors)
{
Console.WriteLine($"Sector Name: {s.SectorName}");
foreach (var ss in s.Subsectors)
{
Console.WriteLine($"Subsector Name: {ss}");
}
Console.WriteLine();
}
}
Console.ReadKey();
}
}

Removing Parent XML element from XML Serialization in C#?

I have a class named Node and inside that i have Property of Type Document Class.
When I serialize it into XML, I get the output as
<Node>
<DocumentType>
<File></File>
</DoumentType>
<Node>
But I want the output as
<Node>
<File></File>
<Node>
Object Code
public class Document
{
[XmlElement(ElementName = "file")]
public string File { get; set; }
}
public class Node
{
public Document NodeDocument
{
get;
set;
}
}
How can I do that using C# xml Serialization?
Following Kami's suggestion, here is the code for your reference. All credit goes to Kami.
public class Node : IXmlSerializable {
public Node() {
NodeDocument = new Document();
}
public Document NodeDocument { get; set; }
public System.Xml.Schema.XmlSchema GetSchema() {
return null;
}
public void ReadXml(XmlReader reader) {
reader.ReadStartElement();
NodeDocument.File = reader.ReadString();
reader.ReadEndElement();
}
public void WriteXml(XmlWriter writer) {
writer.WriteStartElement("file");
writer.WriteString(NodeDocument.File);
writer.WriteEndElement();
}
}
public class Document {
public String File { get; set; }
}
class Program {
static void Main(string[] args) {
var node = new Node();
node.NodeDocument.File = "bbb.txt";
Serialize<Node>("a.xml", node);
node = Deserialize<Node>("a.xml");
Console.WriteLine(node.NodeDocument.File);
Console.Read();
}
static T Deserialize<T>(String xmlFilePath) where T : class {
using (var textReader = File.OpenText(xmlFilePath)) {
using (var xmlTextReader = new XmlTextReader(textReader)) {
var serializer = new XmlSerializer(typeof(T));
return (T)serializer.Deserialize(xmlTextReader);
}
}
}
static void Serialize<T>(String xmlFilePath, T obj) where T : class {
using (var textWriter = File.CreateText(xmlFilePath)) {
using (var xmlTextWriter = new XmlTextWriter(textWriter)) {
var serializer = new XmlSerializer(typeof(T));
serializer.Serialize(xmlTextWriter, obj);
}
}
}
}
Have you considered implementing IXmlSerializable interface - http://msdn.microsoft.com/en-us/library/system.xml.serialization.ixmlserializable.aspx.
You should then be able to write custom serialization/deserialization to facilitate the above.

Categories

Resources