2

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?

3
  • 2
    Can you please post the source for the StationConfiguration class? Commented Jul 16, 2015 at 16:38
  • 1
    we don't know what StationConfiguration is. But using (StringReader stringReader = new StringReader(firstStationConfiguration)) { StationConfiguration sc = (StationConfiguration)serializer.Deserialize(stringReader); might go before your last line. Commented Jul 16, 2015 at 16:40
  • @JacobLam, when I added your code I got this error: "Additional information: There is an error in XML document (1, 2)" ...but I don't see an error... Commented Jul 16, 2015 at 16:54

3 Answers 3

3

Try this

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
using System.IO;
using System.Text.RegularExpressions;

namespace ConsoleApplication1
{
    class Program
    {
        const string FILENAME = @"c:\temp\test.xml";
        static void Main(string[] args)
        {
            Configuration config = new Configuration() {
                configSections = new ConfigSections() {
                    section = new List<Section>() {
                       new Section() { name = "StationsSection", type="AcmeTV_EcFtpClient.StationConfigurationSection, AcmeTV_EcFtpClient"}
                    }
                },
                stationsSection = new StationsSection() {
                    station = new List<Station>() {
                        new Station() { 
                            add = new StationAdd() {
                               comment ="My comment goes here",
                               destinationFolderPath = "C:\\TestInstallation",
                               ftpHostname = "ftp://upload.servername.com/",
                               ftpFolderPath = "myFolderPath/",
                               ftpUsername = "myUserName",
                               ftpPassword = "myFtpPassword",
                               ftpTimeoutInSeconds = 20
                            }
                        }
                    }
                },
                startup = new Startup() {
                    supportedRuntime = new SupportedRuntime() {
                        version = "v2.0.50727"
                    }
                },
                appSettings = new AppSettings() {
                    appSettingAdd = new List<AppSettingAdd>() {
                        new AppSettingAdd() { key= "NameOfService", value="AcmeECClient"},
                        new AppSettingAdd() { key="PollingFrequencyInSeconds", value="60"}
                    }
                }
            };

            XmlSerializer serializer = new XmlSerializer(typeof(Configuration));

            StreamWriter writer = new StreamWriter(FILENAME);
            serializer.Serialize(writer, config);
            writer.Flush();
            writer.Close();
            writer.Dispose();


            XmlSerializer xs = new XmlSerializer(typeof(Configuration));
            XmlTextReader reader = new XmlTextReader(FILENAME);
            Configuration  newConfig = (Configuration)xs.Deserialize(reader);

        }
    }

    [XmlRoot("configuration")]
    public class Configuration
    {
        [XmlElement("configSections")]
        public ConfigSections configSections { get; set; }

        [XmlElement("StationsSection")]
        public StationsSection stationsSection { get; set; }

        [XmlElement("startup")]
        public Startup startup { get; set; }

        [XmlElement("appSettings")]
        public AppSettings appSettings { get; set; }
    }

    [XmlRoot("configSections")]
    public class ConfigSections
    {
        [XmlElement("section")]
        public List<Section> section { get; set; }
    }

    [XmlRoot("section")]
    public class Section
    {
        [XmlAttribute("name")]
        public string name { get; set;}
        [XmlAttribute("type")]
        public string type { get; set; } 
    }

    [XmlRoot("StationsSection")]
    public class StationsSection
    {

        [XmlElement("Stations")]
        public List<Station> station  { get; set; }
    }

    [XmlRoot("Stations")]
    public class Station
    {
        [XmlElement("add")]
        public StationAdd add { get; set; }

    }
    [XmlRoot("add")]
    public class StationAdd
    {
        [XmlAttribute("Comment")]
        public string comment { get; set; }
        [XmlAttribute("DestinationFolderPath")]
        public string destinationFolderPath { get; set; }
        [XmlAttribute("FtpHostname")]
        public string ftpHostname { get; set; }
        [XmlAttribute("FtpFolderPath")]
        public string ftpFolderPath { get; set; }
        [XmlAttribute("FtpUsername")]
        public string ftpUsername { get; set; }
        [XmlAttribute("FtpPassword")]
        public string ftpPassword { get; set; }
        [XmlAttribute("FtpTimeoutInSeconds")]
        public int ftpTimeoutInSeconds { get; set; }
    }

    [XmlRoot("startup")]
    public class Startup
    {
        [XmlElement("supportedRuntime")]
        public SupportedRuntime supportedRuntime { get; set; }
    }

    [XmlRoot("supportedRuntime")]
    public class SupportedRuntime
    {
        [XmlAttribute("version")]
        public string version { get; set; }
    }

    [XmlRoot("appSettings")]
    public class AppSettings
    {
        [XmlElement("add")]
        public List<AppSettingAdd> appSettingAdd { get; set;}
    }

    [XmlRoot("add")]
    public class AppSettingAdd
    {
        [XmlAttribute("key")]
        public string key { get; set; }

        [XmlAttribute("value")]
        public string value { get; set; }
    }


}
​
Sign up to request clarification or add additional context in comments.

2 Comments

jacoblam does have all the classes defined like I did. Also jacoblam and watfy doesn't have arrays/lists for any of the classes. From the names of the tags it appears that some of the object need to be arrays. If you use the other solutions verify that all the data is being read correctly.
I'd love to mark multiple as answers, but that appears to be a yet-unsupported SO feature. :) Yes, I did make the adjustments necessary to support multiple items. Thank you again!
2

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);

    }

Comments

1

Can't quite nail this down in limited time. But perhaps you can work on it; it seems the node was called Stations so it's looking for a Stations class instead of StationConfiguration. But I'm not getting the properties as XML attributes parts yet.

void Main()
{
    const string hardCodedConfigFilePath = @"\\ai-vmdc1\RedirectedFolders\jlambert\Documents\MyApp.exe.config";
    string xmlDocumentText = File.ReadAllText(hardCodedConfigFilePath);
    XmlDocument doc = new XmlDocument();
    //doc.Schemas.Add(, xsdPath
    //Console.WriteLine(xmlDocumentText);
    doc.LoadXml(xmlDocumentText);
    XmlNodeReader reader = new XmlNodeReader(doc.DocumentElement["StationsSection"]);
    string firstStationConfiguration = doc.DocumentElement["StationsSection"].ChildNodes[0].OuterXml;//.InnerXml; //here's the chunk that contains my data
    XmlSerializer ser = new XmlSerializer(typeof(Stations));
    //  Console.WriteLine(xmlDocumentText);
    //object obj = ser.Deserialize(reader);
    Console.WriteLine(firstStationConfiguration);
    using (StringReader stringReader = new StringReader(firstStationConfiguration))
    {
        Stations sc = (Stations)ser.Deserialize(stringReader);
        Console.WriteLine(sc.Comment);
        Console.WriteLine(sc.FtpUsername);
        Console.WriteLine(sc.FtpPassword);
        Console.WriteLine(sc.DestinationFolderPath);
    }
}

// Define other methods and classes here
[Serializable]
public class Stations
{
    [XmlAttribute("Comment")]
    public string Comment { get; set;}
    [XmlAttribute]
    public string FtpUsername { get; set;}
    [XmlAttribute]
    public string FtpPassword { get; set;}
    [XmlAttribute]
    public string DestinationFolderPath { get; set;}
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.