snippetcsharpMinor
How to avoid duplication in my document writer?
Viewed 0 times
writerduplicationavoiddocumenthow
Problem
I have these two methods which are generating two different xml files whose header section is same and detail section varies. The root node is different for both xml files. Here I have two methods written, one for each. I want to optimize the code by avoiding the duplication of code in these two methods. Can you please guide me achieve this?
private string GenerateType1XML(TypeHeader header, List TypeDetailList)
{
StringBuilder builder = new StringBuilder();
using (StringWriter stringWriter = new StringWriter(builder))
{
using (XmlWriter writer = XmlWriter.Create(stringWriter))
{
writer.WriteStartDocument();
writer.WriteStartElement(xmlElementConfig.CreateType1RootNode);
WriteTypeHeader(writer, header);
foreach (TypeDetail typ in TypeDetailList)
{
WriteType1Detail(writer, typ);
}
writer.WriteEndElement();
writer.WriteEndDocument();
}
}
return builder.ToString();
}
private string GenerateType2XML(TypeHeader header, List TypeDetailList)
{
StringBuilder builder = new StringBuilder();
using (StringWriter stringWriter = new StringWriter(builder))
{
using (XmlWriter writer = XmlWriter.Create(stringWriter))
{
writer.WriteStartDocument();
writer.WriteStartElement(xmlElementConfig.CreateType2RootNode);
WriteTypeHeader(writer, header);
foreach (TypeDetail typ in TypeDetailList)
{
WriteType2Detail(writer, typ);
}
writer.WriteEndElement();
writer.WriteEndDocument();
}
}
return builder.ToString();
}Solution
You need to look at what's common to both methods:
Looks like you could have a base class with a
Then you can have a
Now, writing/generating XML is a solved problem, doing that with a
StringBuilder builder = new StringBuilder();
using (StringWriter stringWriter = new StringWriter(builder))
{
using (XmlWriter writer = XmlWriter.Create(stringWriter))
{
writer.WriteStartDocument();
writer.WriteStartElement(/* different in the two methods */);
WriteTypeHeader(writer, header);
foreach (TypeDetail typ in TypeDetailList)
{
/* different in the two methods */
}
writer.WriteEndElement();
writer.WriteEndDocument();
}
}Looks like you could have a base class with a
GenerateXml method calling into abstract members that derived types (Type1XmlGenerator, Type2XmlGenerator... whatever Type1 and Type2 means) can override:public abstract class XmlGenerator
{
protected abstract void WriteDetails(XmlWriter writer, TypeDetail type);
protected abstract string XmlRootNode { get; }
public string GenerateXml(TypeHeader header, IEnumerable details)
{
StringBuilder builder = new StringBuilder();
using (StringWriter stringWriter = new StringWriter(builder))
{
using (XmlWriter writer = XmlWriter.Create(stringWriter))
{
writer.WriteStartDocument();
writer.WriteStartElement(XmlRootNode);
WriteTypeHeader(writer, header);
foreach (TypeDetail detail in details)
{
WriteDetails(writer, detail);
}
writer.WriteEndElement();
writer.WriteEndDocument();
}
}
}
}Then you can have a
class Type1XmlGenerator : XmlGenerator that will override the WriteDetails method with what you currently have in WriteType1Detail, and the XmlRootNode property getter implementation will return xmlElementConfig.CreateType1RootNode.Now, writing/generating XML is a solved problem, doing that with a
StringBuilder is error-prone. You should really look into what LINQ-to-XML (System.Xml.Linq) has in store for you.Code Snippets
StringBuilder builder = new StringBuilder();
using (StringWriter stringWriter = new StringWriter(builder))
{
using (XmlWriter writer = XmlWriter.Create(stringWriter))
{
writer.WriteStartDocument();
writer.WriteStartElement(/* different in the two methods */);
WriteTypeHeader(writer, header);
foreach (TypeDetail typ in TypeDetailList)
{
/* different in the two methods */
}
writer.WriteEndElement();
writer.WriteEndDocument();
}
}public abstract class XmlGenerator
{
protected abstract void WriteDetails(XmlWriter writer, TypeDetail type);
protected abstract string XmlRootNode { get; }
public string GenerateXml(TypeHeader header, IEnumerable<TypeDetail> details)
{
StringBuilder builder = new StringBuilder();
using (StringWriter stringWriter = new StringWriter(builder))
{
using (XmlWriter writer = XmlWriter.Create(stringWriter))
{
writer.WriteStartDocument();
writer.WriteStartElement(XmlRootNode);
WriteTypeHeader(writer, header);
foreach (TypeDetail detail in details)
{
WriteDetails(writer, detail);
}
writer.WriteEndElement();
writer.WriteEndDocument();
}
}
}
}Context
StackExchange Code Review Q#55908, answer score: 5
Revisions (0)
No revisions yet.