2016-07-05 134 views
2

我有這樣的XML:從XML獲取數據分層

<folders> 
    <Folder> 
    <Folder_name>test</Folder_name> 
    <Number_of_files>2</Number_of_files> 
    <File> 
     <File_name>DTLite4461-0327</File_name> 
     <File_size_in_bytes>14682176</File_size_in_bytes> 
    </File> 
    <File> 
     <File_name>TeamViewer_Setup-ioh</File_name> 
     <File_size_in_bytes>11057224</File_size_in_bytes> 
    </File> 
    </Folder> 
    <Folder> 
    <Folder_name>podFolder1</Folder_name> 
    <Number_of_files>1</Number_of_files> 
    <File> 
     <File_name>npp.6.9.1.Installer</File_name> 
     <File_size_in_bytes>4203840</File_size_in_bytes> 
    </File> 
    </Folder> 
    <Folder> 
    <Folder_name>podFolder2</Folder_name> 
    <Number_of_files>1</Number_of_files> 
    <File> 
     <File_name>d-470sqe</File_name> 
     <File_size_in_bytes>2582112256</File_size_in_bytes> 
    </File> 
    </Folder> 
</folders> 

我想打印出來,其中有3列網格視圖:文件名,文件大小和父文件夾的名稱。

我可以從所有節點獲取的所有數據,但我不能得到的文件名連接到相應的父文件夾的名稱和相應的規模

我想是這樣的:

XmlDocument doc = new XmlDocument(); 
doc.Load(xPath); 

XmlNodeList folderNodes = doc.SelectNodes(@"/folders/Folder"); 
int brojac = 0; 

foreach (XmlNode folderNode in folderNodes) 
{ 
    XmlNodeList fileNameNodes = doc.SelectNodes(@"/folders/Folder/File/File_name"); 
    XmlNodeList fileSizeNodes = doc.SelectNodes(@"/folders/Folder/File/Size"); 

    foreach (XmlNode fileName in fileNameNodes) 
    { 
     dgvXML.Rows.Add(fileName.InnerText, folderNode.InnerText, ""); 
    } 
} 

有了這個代碼它會正確輸出父文件夾名稱,但每次都會獲取所有文件,而我無法將其連接到文件大小。

我想在網格視圖是這樣的:

> File name ----------- Parent folder name ------ File size 
> DTLite4461-0327  test      14682176 
> TeamViewer_Setup-ioh test      11057224 
> npp.6.9.1.Installer podFolder1    4203840  
> d-470sqe    podFolder2    2582112256 

這是做到這一點的最好方法是什麼?

+0

我已經回答[類似問題](http://stackoverflow.com/questions/35585310/get-nested-elements-on-xml-with-lambda-and-set-to-listobject)。我的建議是將''子節點添加到''節點,然後:''能夠獲得它們。 –

回答

1

既然你問了最好的方法來做到這一點,我建議使用paste special函數,這將使你的生活變得非常簡單。

基本上你複製了你的xml樣本,使用paste special創建一個類,並使用xmlserializer反序列化一個對象或對象數組。這完全在msdn鏈接中解釋。你會愛上它的。

編輯,因爲您有任何問題:

反序列化操作:

using (XmlSerializer serializer = new XmlSerializer(typeof(folders))) 
{ 
    StreamReader myReader = new StreamReader(path_to_xml_goes_here); 
    folders foldersObject = (folders)serializer.Deserialize(myReader); 
    // Do stuff with the objects here 
} 

XML類:

/// <remarks/> 
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)] 
[System.Xml.Serialization.XmlRootAttribute(Namespace = "", IsNullable = false)] 
public partial class folders 
{ 

    private foldersFolder[] folderField; 

    /// <remarks/> 
    [System.Xml.Serialization.XmlElementAttribute("Folder")] 
    public foldersFolder[] Folder 
    { 
     get 
     { 
      return this.folderField; 
     } 
     set 
     { 
      this.folderField = value; 
     } 
    } 
} 

/// <remarks/> 
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)] 
public partial class foldersFolder 
{ 

    private string folder_nameField; 

    private byte number_of_filesField; 

    private foldersFolderFile[] fileField; 

    /// <remarks/> 
    public string Folder_name 
    { 
     get 
     { 
      return this.folder_nameField; 
     } 
     set 
     { 
      this.folder_nameField = value; 
     } 
    } 

    /// <remarks/> 
    public byte Number_of_files 
    { 
     get 
     { 
      return this.number_of_filesField; 
     } 
     set 
     { 
      this.number_of_filesField = value; 
     } 
    } 

    /// <remarks/> 
    [System.Xml.Serialization.XmlElementAttribute("File")] 
    public foldersFolderFile[] File 
    { 
     get 
     { 
      return this.fileField; 
     } 
     set 
     { 
      this.fileField = value; 
     } 
    } 
} 

/// <remarks/> 
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)] 
public partial class foldersFolderFile 
{ 

    private string file_nameField; 

    private uint file_size_in_bytesField; 

    /// <remarks/> 
    public string File_name 
    { 
     get 
     { 
      return this.file_nameField; 
     } 
     set 
     { 
      this.file_nameField = value; 
     } 
    } 

    /// <remarks/> 
    public uint File_size_in_bytes 
    { 
     get 
     { 
      return this.file_size_in_bytesField; 
     } 
     set 
     { 
      this.file_size_in_bytesField = value; 
     } 
    } 
} 
+0

謝謝,但它不適用於我輸入問題的xml。 – Zorge

+1

@Bopa我只是試過,它的工作完美。我會更新答案 – Gaspa79

0

嘗試XML LINQ:

using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Data; 
using System.Drawing; 
using System.Linq; 
using System.Text; 
using System.Windows.Forms; 
using System.Xml; 
using System.Xml.Linq; 

namespace WindowsFormsApplication1 
{ 
    public partial class Form1 : Form 
    { 
     const string FILENAME = @"c:\temp\test.xml"; 
     public Form1() 
     { 
      InitializeComponent(); 
      DataTable dt = new DataTable(); 
      dt.Columns.Add("File Name", typeof(string)); 
      dt.Columns.Add("File Size", typeof(string)); 
      dt.Columns.Add("Parent", typeof(string)); 

      XDocument doc = XDocument.Load(FILENAME); 
      foreach (XElement folder in doc.Descendants("Folder").AsEnumerable()) 
      { 
       string folder_name = folder.Element("Folder_name").Value; 
       foreach (XElement file in folder.Descendants("File").AsEnumerable()) 
       { 
        dt.Rows.Add(new object[] { 
         file.Element("File_name").Value, 
         file.Element("File_size_in_bytes").Value, 
         folder_name 
        }); 

       } 
      } 
      dataGridView1.DataSource = dt; 
     } 
    } 
} 
1

好... 您應該重新考慮您的xml結構,因爲File不在「分組」元素內,如Files。 XML結構應該是這樣的:

Folders 
    +-Folder 
     +-Files (you missed that) 
     +-File 

當然,有一種方法來變通方法,但需要使用的XmlDocumentXDocument class + LiqToXml代替。

看看例子:

string xcontent = @"<?xml version='1.0' ?>..."; //replace ... with xml content 
//i decided to not post entire content of xml due to clarity of code 

XDocument xdoc = XDocument.Parse(xcontent); 
var data = xdoc.Descendants("Folder") 
       .Select(x=> new 
        { 
         FolderName = x.Element("Folder_name").Value, 
         Files = x.Descendants("File") 
         .Select(a=> 
          Tuple.Create(
           a.Element("File_name").Value, 
           a.Element("File_size_in_bytes").Value) 
         ).ToList() 
        }) 
       .SelectMany(x=>x.Files. 
        Select(y=> new 
        { 
         FolderName =x.FolderName, 
         FileName = y.Item1, 
         FileSize=y.Item2 
        })) 
       .ToList(); 

結果:

FolderName FileName    FileSize 
test  DTLite4461-0327  14682176 
test  TeamViewer_Setup-ioh 11057224 
podFolder1 npp.6.9.1.Installer 4203840 
podFolder2 d-470sqe    2582112256 

什麼date查詢呢?

第一個select語句獲取文件夾名稱和文件列表屬於該文件夾。通過這種方式:

FolderName | Files(a list) 
--------------------------------------------------- 
test  | Item1(FileName)  Item2(FileSize) 
      |-------------------------------------- 
      | DTLite4461-0327  14682176 
      | TeamViewer_Setup-ioh 11057224 
---------------------------------------------------- 
...  | ... (and so on) 

select聲明(SelectMany)獲取以上數據,並將它們轉成目的地的結果集。

試試!