Introduction
This article provides some simple adapters to help separate XML documents from the business logic. The reader allows you to grab a child's value or a child's attribute. It also allows you to check to see if a child exists. It lets you grab a node subset --> basically, if you sent it a "child list", it would return a NodeList of the grand children:
<currNode>
<child1/>
<child2/>
<childList>
<grandchild>
<property1/>
<property2/>
</grandchild>
<grandchild>
<property1/>
<property2/>
</grandchild>
</childList>
<child4/>
</currNode>
The writer allows for creating nodes with values. (I just added the attribute part. Not sure if it works, but it compiles.) It also allows for appending those nodes. Lots of overloaded methods are available. The writer also allows for printing the document.
Add and change the code as you will:
#region XmlWriterAdapter and XmlReaderAdapter
#region XmlReaderAdapter
public class XmlReaderAdapter {
#region Attributes
private XmlNode currNode;
#endregion
#region Constructors
public XmlReaderAdapter(XmlNode currNode){
this.currNode = currNode;
}
public XmlReaderAdapter(XmlDocument doc):this(doc.FirstChild){
}
#endregion
#region Getting text and attribute values
public string this[string child]{
get{
return currNode.SelectSingleNode("child::" + child).InnerText;
}
}
public string this[string child, string attribute]{
get{
return currNode.SelectSingleNode("child::" +
child).Attributes[attribute].Value;
}
}
#endregion
#region Check if child exists
public bool hasChildValue(string child){
return (hasChild(child) && (this[child].Length>0));
}
public bool hasChild(string child){
return (this.currNode.SelectSingleNode("child::"+child)!=null);
}
#endregion
#region Get Sub-Nodes - Old version
public XmlNodeList getSubNodeCollection(string collectionWrapperChild){
return currNode.SelectSingleNode("child::" +
collectionWrapperChild).ChildNodes;
}
#endregion
#region Get SubNode / Children Adapter Collections - new version
public XmlReaderAdapterCollection
getSubNodeAdapterCollection(string collectionWrapperChild){
return new XmlReaderAdapterCollection(currNode.SelectSingleNode(
"child::" + collectionWrapperChild).ChildNodes);
}
public XmlReaderAdapterCollection getAllChildren(){
return new XmlReaderAdapterCollection(currNode.ChildNodes);
}
#endregion
}
#endregion
#region XmlReaderAdapterCollection
[Serializable()]
public class XmlReaderAdapterCollection : CollectionBase{
public XmlReaderAdapterCollection(){
}
public XmlReaderAdapterCollection(XmlNodeList nodes){
foreach (XmlNode node in nodes){
this.Add(new XmlReaderAdapter(node));
}
}
public XmlReaderAdapter this[int index]{
get{
return (XmlReaderAdapter)List[index];
}
set{
List[index] = value;
}
}
public int Add(XmlReaderAdapter value){
return(List.Add(value));
}
public int IndexOf(XmlReaderAdapter value){
return(List.IndexOf(value));
}
public void Insert(int index, XmlReaderAdapter value){
List.Insert(index, value);
}
public void Remove(XmlReaderAdapter value){
List.Remove(value);
}
public bool Contains(XmlReaderAdapter value){
return(List.Contains(value));
}
}
#endregion
#region XmlWriterAdapter
public class XmlWriterAdapter{
#region Properties and Attributes
private XmlDocument doc;
private string docNamespace;
private XmlNode rootNode;
public XmlNode RootNode{
get{
return this.rootNode;
}
}
public XmlDocument Doc{
get{
return this.doc;
}
}
#endregion
#region Constructors
public XmlWriterAdapter(string rootNodeName):
this(string.Empty,rootNodeName){
}
public XmlWriterAdapter(string docNamespace, string rootNodeName){
this.docNamespace = docNamespace;
this.doc = new XmlDocument();
rootNode = MakeAndSetElement(rootNodeName);
doc.AppendChild(rootNode);
}
#endregion
#region Creating Elements with inner text
public XmlNode MakeAndSetElement(string name){
return doc.CreateNode(XmlNodeType.Element, name, docNamespace);
}
public XmlNode MakeAndSetElement(string name, string value){
XmlNode field = MakeAndSetElement(name);
field.InnerText = value;
return field;
}
#endregion
#region Add Attribute
public void MakeAndSetAttribute(string name, string value, XmlNode parent){
XmlAttribute field = doc.CreateAttribute(name, docNamespace);
field.Value = value;
parent.Attributes.Append(field);
}
#endregion
#region Append Element
public XmlNode AppendElement(string name, string value, XmlNode parent){
return AppendElement(MakeAndSetElement(name,value),parent);
}
public XmlNode AppendElement(string name, XmlNode parent){
return AppendElement(MakeAndSetElement(name),parent);
}
public XmlNode AppendElement(XmlNode child, XmlNode parent){
parent.AppendChild(child);
return child;
}
#endregion
#region AppendElementToRoot
public XmlNode AppendElementToRoot(string name){
return AppendElementToRoot(name,string.Empty);
}
public XmlNode AppendElementToRoot(string name, string value){
return AppendElementToRoot(MakeAndSetElement(name,value));
}
public XmlNode AppendElementToRoot(XmlNode child){
return AppendElement(child,this.rootNode);
}
#endregion
#region Write XML
public string WriteIndentedXML(){
StringWriter strWriter = new StringWriter();
XmlTextWriter xmlWriter = new XmlTextWriter(strWriter);
xmlWriter.Formatting = Formatting.Indented;
doc.WriteTo(xmlWriter);
xmlWriter.Flush();
strWriter.Flush();
return strWriter.ToString();
}
public string WriteXML(){
StringWriter strWriter = new StringWriter();
XmlTextWriter xmlWriter = new XmlTextWriter(strWriter);
xmlWriter.Formatting = Formatting.None;
doc.WriteTo(xmlWriter);
xmlWriter.Flush();
strWriter.Flush();
return strWriter.ToString();
}
#endregion
}
#endregion
#endregion
History
Update notes:
- Added an XML adapter reader collection and some extra constructors / methods.
- Added an attribute writer for
XmlWriterAdapter.
Update clarifications:
- These adapters are just to simplify things. The
XmlDocument in ASP.NET is very verbose.
- If you want to open and modify a pre-existing
XmlDocument, you'll have to write your own adapter. This doesn't really happen that often in what I do.