|
|
XML Document Wrapper ClassMake Retrieving XML Nodes Easy | | Is there an easier way to extract nodes from an App Config File than using the IConfigurationSectionHandler Interface? It seems a little cumbersome to simply retrieve one node from the AppConfig file. Yes, there is a simple way to do it. In this article I will demonstrate a small wrapper class that I have written for the XmlDocument object.
I originally was using the IConfigurationSectionHandler Interface to write a ConfigurationHandler Class, but found it a little cumbersome, seeing that the AppConfig file itself has to be modified to facilitate the use of the IConfigurationSectionHandler Interface.
The Wrapper class that I have written will, by default, load the application's config file, or alternately load any XML file passed as a parameter to the constructor. Once the constructor is called, you then call the GetSingleNode method to retrieve the inner text of an XML node. You must pass the completely qualified node whose value you want to retrieve. Figure 1 demonstrates the calling code to the wrapper class. I am using this code, first to get the path to AppStart.exe.Config, which is the shim application for the Updater Application Block. I then read it to get the path to the current version of a self updating application.
Figure 1 - Calling the Wrapper.
// first we get the path to the appStart.exe.config
// it has already been modified by the upadter to point
// to the new exe path. Passing an empty string will
// cause the wrapper to default to the current app config file
xCH = new XMLConfigurationHandler("");
// next line returns
// "C:\Self Updating Application\DemoApp\AppStart.exe.config"
string appStartConfig =
xCH.GetSingleNode(
"configuration/appUpdater/UpdaterConfiguration/application/client/xmlFile");
// Next, I want to get the path to the current self updating application
// so I create a new instance of the wrapper passing the path
// retrieved in the last call.
xCH = new XMLConfigurationHandler(appStartConfig);
// returns "C:\Self Updating Application\DemoApp\2.0.0.0"
string newVersionAppPath =
xCH.GetSingleNode(
"configuration/appStart/ClientApplicationInfo/appFolderName");
string pathToAppStartConfigFile = Path.Combine(myPath,"AppStart.exe.config");
if (!xCH.ReplaceSingleNodeValue(xPathToxmlFile ,pathToAppStartConfigFile))
return false;
|
Now, for a little trickier touch. Thus far, I have been dealing with nodes that did not have attributes, such as the following:
<xmlFile>C:\Self Updating Application\DemoApp\2.0.0.0</xmlFile>
|
However, what if there are attributes such as the following?
<xmlFile>filePath = "C:\Self Updating Application\DemoApp\1.0.0.0" appName = "Test.exe"</xmlFile>
|
Now, just getting the innertext with the normal xPath will work, and the replace, likewise, won't work. But with a minor modification to the xPath, you can do the job. In the xPath shown below, note that the node that I am retrieving is "logListener", but within that node is an attribute named logPath. The node innertext actually looks as follows.
<logListener logPath = "C:\Self Updating Application\DemoApp\1.0.0.0\UpdaterLog.txt" />
|
I need to change it to the following.
<logListener logPath = "C:\Program Files\MyApp\UpdaterLog.txt" />
|
In order to do that, I will add "@logPath" to the normal xPath so that it will look as follows.
string xPath = "configuration/appUpdater/UpdaterConfiguration/application/client/@logPath";
|
Then, I can use the follow code to replace the logPath attribute.
string logPath = Path.Combine(myPath, "UpdaterLog.txt");
if (!xCH.ReplaceSingleNodeValue(xPathToLogListener, logPath))
return false;
|
The result will be:
<logListener logPath = "C:\Program Files\MyApp\UpdaterLog.txt" />
|
Lastly, until this point, I have been using the fully qualified xPath string. In other words, I have coded every key to get to the node that I was trying to retrieve or replace. Actually, you can shortcut the xPath to only include the key names that are required to get to the exact node. In other words, if there is only one <logListener> node in the file, you can shortcut it to "//logListener/@logPath". Be aware, however, that if you do this and there are multiple nodes with the name, <logListener>, you will only get the first one, using the node.SelectSingleNode() method used in the XMLConfiguration code shown in Figure 2. Also, know that the xPath string is case-sensitive and failure to spell the xPath exactly right will result in a failure to retrieve or replace data in the Xml Document.
Figure 2 demonstrates the code for the Wrapper Class written in C#.
Figure 2 - Wrapper Class Code
using System;
using System.Xml;
namespace InfoPro.UABWrapper
{
/// <summary>
/// This is a simple class wrapper for the xml document object.
/// It allow reading and updating the innertext of a single node
/// that can be specified by an xPath to the node. If no file is
/// passed to the constructor, the appConfig file will be loaded.
/// Passing a filename of an xml file will load that file.
///
public class XMLConfigurationHandler
{
#region Class Level Variables & Properties
private XmlDocument _doc;
private string _XmlFileName;
public string XmlFileName
{
get{return _XmlFileName;}
set{_XmlFileName = value;}
}
public XmlDocument doc
{
get{return _doc;}
set{_doc = value;}
}
#endregion
#region Constructor
/// <summary>
/// Load the app config file for this app
/// if xmlFile is empty, otherwise load
/// xmlFile. If there is no valid file, the constructor will
/// cause an unhandled exception.
///
///
public XMLConfigurationHandler(string xmlFile)
{
doc = new XmlDocument();
if(xmlFile==string.Empty)
{
doc.Load( AppDomain.CurrentDomain.SetupInformation.ConfigurationFile );
XmlFileName = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile;
}
else
{
doc.Load(xmlFile);
XmlFileName = xmlFile;
}
}
#endregion
#region Public Methods
/// <summary>
/// Return inner text of node specified by xPath.
/// If xPath is not valid, a null reference exception
/// will be generated on the call to SelectSingleNode.
///
///
/// <returns>
public string GetSingleNode(string xPath)
{
try
{
string innerText = doc.SelectSingleNode(xPath).InnerText;
return innerText;
}
catch(System.Exception ex)
{
return string.Empty;
}
}
/// <summary>
/// This method will replac the text into the xml document
/// for the node(xPath) passed.
/// If xPath is not valid, a null reference exception
/// will be generated on the call to SelectSingleNode.
///
///
///
/// <returns>
public bool ReplaceSingleNodeValue(string xmlPath, string text)
{
try
{
System.Xml.XmlNode node = doc.SelectSingleNode(xmlPath);
node.InnerText = text;
doc.Save(XmlFileName);
return true;
}
catch
{
return false;
}
}
#endregion
}
}
| |
|