正在从XML文件检索数据

本文关键字:检索 数据 文件 XML | 更新日期: 2023-09-27 17:59:45

我似乎在用C#检索XML值时遇到了问题,我知道这是由于我对C#和.XML.的了解非常有限

我收到了以下XML文件

<PowerBuilderRunTimes>
    <PowerBuilderRunTime>
        <Version>12</Version>
        <Files>
            <File>EasySoap110.dll</File>
            <File>exPat110.dll</File>
            <File>pbacc110.dll</File>
        </File>
     </PowerBuilderRunTime>
</PowerBuilderRunTimes>

我要处理XML文件,并确保中的每个文件都存在于文件夹中(这是最简单的部分)。这是XML文件的处理,我一直很难处理。以下是我迄今为止所做的:

var runtimeXml = File.ReadAllText(string.Format("{0}''{1}", configPath, Resource.PBRuntimes));
var doc = XDocument.Parse(runtimeXml);
var topElement = doc.Element("PowerBuilderRunTimes");
var elements = topElement.Elements("PowerBuilderRunTime");
foreach (XElement section in elements)
{
    //pbVersion is grabbed earlier. It is the version of PowerBuilder
    if( section.Element("Version").Value.Equals(string.Format("{0}", pbVersion ) ) )
    {
        var files = section.Elements("Files");
        var fileList = new List<string>();
        foreach (XElement area in files)
        {
            fileList.Add(area.Element("File").Value);
        }
    }
}

我的问题是,字符串列表只填充了一个值"EasySoap110.dll",其他的都被忽略了。有人能帮帮我吗,因为我不知所措。

正在从XML文件检索数据

看看这个位:

var files = section.Elements("Files");
var fileList = new List<string>();
foreach (XElement area in files)
{
    fileList.Add(area.Element("File").Value);
}

您要迭代每个Files元素,然后找到其中的第一个File元素。只有一个Files元素-您需要迭代其中的File元素。

然而,肯定有更好的方法可以做到这一点。例如:

var doc = XDocument.Load(Path.Combine(configPath, Resource.PBRuntimes));
var fileList = (from runtime in doc.Root.Elements("PowerBuilderRunTime")
                where (int) runtime.Element("Version") == pbVersion
                from file in runtime.Element("Files").Elements("File")
                select file.Value)
               .ToList();

请注意,如果有多个匹配的PowerBuilderRunTime元素,这将创建一个包含所有的列表,的文件都是这些元素。这可能不是你想要的。例如,您可能想要:

var doc = XDocument.Load(Path.Combine(configPath, Resource.PBRuntimes));
var runtime = doc.Root
                 .Elements("PowerBuilderRunTime")
                 .Where(r => (int) r.Element("Version") == pbVersion)
                 .Single();
var fileList = runtime.Element("Files")
                      .Elements("File")
                      .Select(x => x.Value)
                      .ToList();

这将验证是否有一个匹配的运行时。

问题是,XML中只有一个元素,有多个子元素。foreach循环只对单个元素执行一次,而不对其子元素执行。

这样做:

var fileSet = files.Elements("File");
foreach (var file in fileSet) {
    fileList.Add(file.Value);
}

其在所有子元素上循环。

我一直更喜欢使用读取器来读取自行生成的XML配置文件。如果你只做一次,那可能会让人不知所措,但读者会更快、更便宜。

public static class PowerBuilderConfigParser
{
    public static IList<PowerBuilderConfig> ReadConfigFile(String path)
    {
        IList<PowerBuilderConfig> configs = new List<PowerBuilderConfig>();
        using (FileStream stream = new FileStream(path, FileMode.Open))
        {
            XmlReader reader = XmlReader.Create(stream);
            reader.ReadToDescendant("PowerBuilderRunTime");
            do
            {
                PowerBuilderConfig config = new PowerBuilderConfig();
                ReadVersionNumber(config, reader);
                ReadFiles(config, reader);
                configs.Add(config);
                reader.ReadToNextSibling("PowerBuilderRunTime");
            } while (reader.ReadToNextSibling("PowerBuilderRunTime"));
        }
        return configs;
    }
    private static void ReadVersionNumber(PowerBuilderConfig config, XmlReader reader)
    {
        reader.ReadToDescendant("Version");
        string version = reader.ReadString();
        Int32 versionNumber;
        if (Int32.TryParse(version, out versionNumber))
        {
            config.Version = versionNumber;
        }
    }
    private static void ReadFiles(PowerBuilderConfig config, XmlReader reader)
    {
        reader.ReadToNextSibling("Files");
        reader.ReadToDescendant("File");
        do
        {
            string file = reader.ReadString();
            if (!string.IsNullOrEmpty(file))
            {
                config.AddConfigFile(file);
            }
        } while (reader.ReadToNextSibling("File"));
    }
}
public class PowerBuilderConfig
{
    private Int32 _version;
    private readonly IList<String> _files;
    public PowerBuilderConfig()
    {
        _files = new List<string>();
    }
    public Int32 Version
    {
        get { return _version; }
        set { _version = value; }
    }
    public ReadOnlyCollection<String> Files
    {
        get { return new ReadOnlyCollection<String>(_files); }
    }
    public void AddConfigFile(String fileName)
    {
        _files.Add(fileName);
    }
}

另一种方法是使用XmlSerializer。

[Serializable]
[XmlRoot]
public class PowerBuilderRunTime
{
 [XmlElement]
 public string Version {get;set;}
 [XmlArrayItem("File")]
 public string[] Files {get;set;} 
 public static PowerBuilderRunTime[] Load(string fileName)
 {
    PowerBuilderRunTime[] runtimes;
    using (var fs = new FileStream(fileName, FileMode.Open, FileAccess.Read))
        {
            var reader = new XmlTextReader(fs);
            runtimes = (PowerBuilderRunTime[])new XmlSerializer(typeof(PowerBuilderRunTime[])).Deserialize(reader);
        }
     return runtimes;
 }
}

您可以获得所有强类型的运行时,并使用每个PowerBuilderRunTime的Files属性循环遍历所有字符串文件名。

var runtimes = PowerBuilderRunTime.Load(string.Format("{0}''{1}", configPath, Resource.PBRuntimes));

您应该尝试用简单的XPath查询替换这些内容。

        string configPath;
        System.Xml.XPath.XPathDocument xpd = new System.Xml.XPath.XPathDocument(cofigPath);
        System.Xml.XPath.XPathNavigator xpn = xpd.CreateNavigator();
        System.Xml.XPath.XPathExpression exp = xpn.Compile(@"/PowerBuilderRunTimes/PwerBuilderRunTime/Files//File");
        System.Xml.XPath.XPathNodeIterator iterator = xpn.Select(exp);
        while (iterator.MoveNext())
        {
            System.Xml.XPath.XPathNavigator nav2 = iterator.Current.Clone();
            //access value with nav2.value
        }