2011-06-21 52 views
5

Tôi dường như đang gặp sự cố khi truy xuất giá trị XML bằng C#, điều tôi biết là do kiến ​​thức rất hạn chế về C# và .XML của tôi.Lấy dữ liệu từ tệp XML

tôi đã được đưa ra tập tin XML sau

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

tôi để xử lý các tập tin XML và chắc chắn rằng mỗi người trong số các tập tin trong tồn tại trong thư mục (đó là phần dễ dàng). Đó là việc xử lý tệp XML mà tôi gặp khó khăn. Dưới đây là những gì tôi đã thực hiện cho đến thời điểm này:

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

Vấn đề của tôi là Danh sách chuỗi chỉ được điền một giá trị, "EasySoap110.dll" và mọi thứ khác bị bỏ qua. Ai đó có thể giúp tôi, vì tôi đang thua lỗ.

+0

Vui lòng không bắt đầu chủ đề của bạn bằng "C#". Đó là những gì các thẻ cho. –

Trả lời

10

Nhìn vào bit này:

var files = section.Elements("Files"); 

var fileList = new List<string>(); 

foreach (XElement area in files) 
{ 
    fileList.Add(area.Element("File").Value); 
} 

Bạn đang lặp lại trên mỗi phần tử Files, và sau đó tìm phần tử đầu tiên File bên trong nó. Chỉ có một phần tử Files - bạn cần phải lặp qua các thành phần File trong đó.

Tuy nhiên, chắc chắn có những cách tốt hơn để thực hiện việc này. Ví dụ:

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

Lưu ý rằng nếu có nhiều phù hợp với PowerBuilderRunTime yếu tố, mà sẽ tạo ra một danh sách với tất cả các tập tin của tất cả những yếu tố này. Đó có thể không phải là điều bạn muốn. Ví dụ, bạn có thể muốn:

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

Điều đó sẽ xác nhận rằng có chính xác một khớp runtime.

+1

Tuyệt vời, đó là chính xác những gì tôi đang tìm kiếm! Cảm ơn bạn đã giúp tôi hiểu! –

-1

Bạn nên thử thay thế công cụ này bằng truy vấn XPath đơn giản.

 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 
     } 
+0

Không có liên kết và không giải thích thêm, có thể khó theo dõi. –

2

Vấn đề là, chỉ có một phần tử trong XML của bạn, với nhiều trẻ em. Bạn foreach vòng lặp chỉ thực hiện một lần, cho các yếu tố duy nhất, không cho con cái của nó.

Làm như thế này:

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

mà vòng qua tất cả các yếu tố trẻ em.

0

Tôi luôn ưu tiên sử dụng trình đọc để đọc tệp cấu hình XML trong nhà. Nếu bạn chỉ làm điều này một khi nó có thể bị giết, nhưng người đọc nhanh hơn và rẻ hơn.

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); 
    } 
} 
+0

Cũng với OP, XML của bạn không được định dạng đúng, đầu của bạn kết thúc bằng. –

0

Một cách khác là sử dụng 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; 
} 
} 

Bạn có thể nhận được tất cả các runtimes gõ mạnh mẽ, và sử dụng mỗi thuộc tính tệp PowerBuilderRunTime để lặp qua tất cả các tên tệp chuỗi.

var runtimes = PowerBuilderRunTime.Load(string.Format("{0}\\{1}", configPath, Resource.PBRuntimes)); 
Các vấn đề liên quan