2016-07-05 3 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, создаете класс с использованием специальной вставки и десериализуете объект или массив объектов с помощью xmlserializer. Это прекрасно объясняется ссылкой msdn. Тебе это понравится.

EDIT, так как у вас возникли проблемы:

десериализовать сделать:

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

Try 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 

Конечно, есть способ обойти это, но требует, чтобы использовать XDocument class + LiqToXml вместо XmlDocument.

Посмотрите на пример:

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) получает выше данных и перенести их в целевой результирующий.

Попробуйте!