I've seen several SO posts regarding this same type of question but I cannot seem to get this to work.
I've got this XML file (in its entirety):
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="StationsSection" type="AcmeTV_EcFtpClient.StationConfigurationSection, AcmeTV_EcFtpClient"/>
</configSections>
<StationsSection>
<Stations>
<add Comment="My comment goes here"
DestinationFolderPath="C:\TestInstallation"
FtpHostname="ftp://upload.servername.com/"
FtpFolderPath="myFolderPath/"
FtpUsername="myUserName"
FtpPassword="myFtpPassword"
FtpTimeoutInSeconds="20" />
</Stations>
</StationsSection>
<startup>
<supportedRuntime version="v2.0.50727"/>
</startup>
<appSettings>
<add key="NameOfService" value="AcmeECClient"/>
<add key="PollingFrequencyInSeconds" value="60"/>
</appSettings>
</configuration>
Here's the code for StationConfiguration:
public class StationConfiguration
{
readonly Regex OnlyAlphaNumericWithNoSpaces = new Regex("^[a-zA-Z0-9]*$");
public StationConfiguration() { }
public StationConfiguration(string comment, string ftpUsername, string ftpPassword, string destinationFolderPath)
{
Comment = comment;
FtpUsername = ftpUsername;
FtpPassword = ftpPassword;
DestinationFolderPath = destinationFolderPath;
}
public bool IsValidStation()
{
return OnlyAlphaNumericWithNoSpaces.IsMatch(Comment);
}
public bool IsValidUsername()
{
return OnlyAlphaNumericWithNoSpaces.IsMatch(FtpUsername);
}
public bool IsValidPassword()
{
return FtpPassword.Contains(' ') == false;
}
public bool IsValidFolderPath()
{
return Directory.Exists(DestinationFolderPath);
}
private string _comment;
public string Comment
{
get
{
return _comment;
}
set
{
_comment = value.ToUpper();
}
}
public string FtpUsername { get; set; }
public string FtpPassword { get; set; }
public string DestinationFolderPath { get; set; }
}
Here's my C# code that's attempting the parsing:
const string hardCodedConfigFilePath = @"C:\Program Files (x86)\MyApp.exe.config";
string xmlDocumentText = File.ReadAllText(hardCodedConfigFilePath);
XmlDocument doc = new XmlDocument();
doc.LoadXml(xmlDocumentText);
XmlNodeReader reader = new XmlNodeReader(doc.DocumentElement["StationsSection"]);
string firstStationConfiguration = doc.DocumentElement["StationsSection"].ChildNodes[0].InnerXml; //here's the chunk that contains my data
XmlSerializer ser = new XmlSerializer(typeof(StationConfiguration));
object obj = ser.Deserialize(reader);
The string called firstStationConfiguration
contains this:
<add Comment="My comment goes here"
DestinationFolderPath="C:\TestInstallation"
FtpHostname="ftp://upload.servername.com/"
FtpFolderPath="myFolderPath/"
FtpUsername="myUsername"
FtpPassword="abcdefg" FtpTimeoutInSeconds="20" />
When the last C# line is executed, this is thrown:
An unhandled exception of type 'System.InvalidOperationException' occurred in System.Xml.dll Additional information: There is an error in the XML document.
Please... How can I transform the Stations
node (which may contain multiples) into C# objects?
You try to deserialize only a part of your Xml document that is why it is considered as an invalid Xml document. To make it work you need to create a new Xml document with a root element and add an Xml declaration. This needs an extra class. The properties in your StationConfiguration class needs to be decorated with the XMLAttribute Attribute.(In the sample the test.xml file is the same as your config file)
A faster way is probably to get directly the attributes from your node and to create an instance of your class (solution2)
Finally you can use Linq to do the job (solution 3)
public class Stations
{
[XmlElement(ElementName = "add", Namespace = "")]
public StationConfiguration StationConfiguration { get; set; }
}
[XmlType(AnonymousType = true, Namespace = "")]
public class StationConfiguration
{
readonly Regex OnlyAlphaNumericWithNoSpaces = new Regex("^[a-zA-Z0-9]*$");
public StationConfiguration() { }
public StationConfiguration(string comment, string ftpUsername, string ftpPassword, string destinationFolderPath)
{
Comment = comment;
FtpUsername = ftpUsername;
FtpPassword = ftpPassword;
DestinationFolderPath = destinationFolderPath;
}
public bool IsValidStation()
{
return OnlyAlphaNumericWithNoSpaces.IsMatch(Comment);
}
public bool IsValidUsername()
{
return OnlyAlphaNumericWithNoSpaces.IsMatch(FtpUsername);
}
public bool IsValidPassword()
{
return FtpPassword.Contains(' ') == false;
}
public bool IsValidFolderPath()
{
return Directory.Exists(DestinationFolderPath);
}
private string _comment;
[XmlAttribute]
public string Comment
{
get
{
return _comment;
}
set
{
_comment = value.ToUpper();
}
}
[XmlAttribute]
public string FtpUsername { get; set; }
[XmlAttribute]
public string FtpPassword { get; set; }
[XmlAttribute]
public string DestinationFolderPath { get; set; }
}
class Program
{
private static void Main(string[] args)
{
const string hardCodedConfigFilePath = @"test.xml";
sol1(hardCodedConfigFilePath);
sol2(hardCodedConfigFilePath);
sol3(hardCodedConfigFilePath);
}
public static void sol1(string hardCodedConfigFilePath)
{
string xmlDocumentText = File.ReadAllText(hardCodedConfigFilePath);
var doc = new XmlDocument();
doc.LoadXml(xmlDocumentText);
var docElem = new XmlDocument();
docElem.CreateXmlDeclaration("1.0", "utf-8", "yes");
var node = doc.DocumentElement["StationsSection"];
//Create a document fragment.
var docFrag = docElem.CreateDocumentFragment();
//Set the contents of the document fragment.
docFrag.InnerXml = node.InnerXml;
//Add the document fragment to the
// document.
docElem.AppendChild(docFrag);
var reader = new XmlNodeReader(docElem);
var ser = new XmlSerializer(typeof(Stations));
object obj = ser.Deserialize(reader);
}
public static void sol2(string hardCodedConfigFilePath)
{
string xmlDocumentText = File.ReadAllText(hardCodedConfigFilePath);
var doc = new XmlDocument();
doc.LoadXml(xmlDocumentText);
var attr = doc.DocumentElement["StationsSection"].ChildNodes[0].ChildNodes[0].Attributes;
// Check that attributes exist ...
var stationConfiguration = new StationConfiguration(attr["Comment"].Value
, attr["FtpUsername"].Value
, attr["FtpPassword"].Value
, attr["DestinationFolderPath"].Value);
}
public static void sol3(string hardCodedConfigFilePath)
{
var xdoc = XElement.Load(hardCodedConfigFilePath);
var config = xdoc.Descendants("Stations").Elements("add").FirstOrDefault();
// Check that attributes exist ...
var stationConfiguration = new StationConfiguration(config.Attribute("Comment").Value
, config.Attribute("FtpUsername").Value
, config.Attribute("FtpPassword").Value
, config.Attribute("DestinationFolderPath").Value);
}