正在将 XML 文档转换为对象

Converting XML document into object

我看过几个关于此类问题的 SO 帖子,但我似乎无法解决这个问题。

我有这个 XML 文件(完整):

<?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>

这是 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; }
}

这是我尝试解析的 C# 代码:

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

名为 firstStationConfiguration 的字符串包含:

<add Comment="My comment goes here" 
     DestinationFolderPath="C:\TestInstallation"
     FtpHostname="ftp://upload.servername.com/" 
     FtpFolderPath="myFolderPath/"    
     FtpUsername="myUsername"
     FtpPassword="abcdefg" FtpTimeoutInSeconds="20" />

执行最后一行 C# 时,抛出:

An unhandled exception of type 'System.InvalidOperationException' occurred in System.Xml.dll Additional information: There is an error in the XML document.

请...如何将 Stations 节点(可能包含多个)转换为 C# 对象?

无法在有限的时间内完全确定这一点。但也许你可以继续努力;该节点似乎名为 Stations,因此它正在寻找 Stations class 而不是 StationConfiguration。但是我还没有得到 XML 属性部分的属性。

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

试试这个

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


}
​

您尝试仅反序列化 Xml 文档的一部分,这就是它被视为无效 Xml 文档的原因。要使其工作,您需要创建一个包含根元素的新 Xml 文档并添加一个 Xml 声明。这需要一个额外的class。 StationConfiguration class 中的属性需要使用 XMLAttribute 属性进行修饰。(在示例中,test.xml 文件与您的配置文件相同)

一种更快的方法可能是直接从您的节点获取属性并创建您的 class(解决方案 2)

的实例

终于可以使用 Linq 完成这项工作了(解决方案 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);

    }