从XML文件中检索数据

时间:2011-06-21 19:58:22

标签: c# .net xml

我似乎遇到了使用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”,其他一切都被忽略了。有人可以帮助我,因为我不知所措。

5 个答案:

答案 0 :(得分:10)

看看这一点:

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

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

答案 1 :(得分:2)

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

做这样的事情:

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

循环遍历所有子元素。

答案 2 :(得分:0)

我总是喜欢使用阅读器来阅读自己开发的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);
    }
}

答案 3 :(得分:0)

另一种方法是使用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));

答案 4 :(得分:-1)

您应该尝试使用简单的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
        }