2016-07-05 19 views
2

Ich habe diese xml:Abrufen von Daten aus XML hierarchisch

<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> 

Ich will es in der Rasterdarstellung drucken, die drei Spalten: Dateiname, Dateigröße und Parent Ordnernamen.

ich alle Daten von allen Knoten bekommen, aber ich kann nicht Dateinamen eine Verbindung zum entsprechenden übergeordneten Ordnernamen und entsprechende Größe

ich so versucht erhalten:

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

Mit diesem Code Es druckt den Namen des übergeordneten Ordners korrekt aus, aber alle Dateien werden jedes Mal abgerufen und ich kann sie nicht mit der Dateigröße verbinden.

Ich mag so etwas wie dies in der Rasterdarstellung erhalten:

> 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 

Welches ist der beste Weg, dies zu tun ist?

+0

Ich hatte bereits auf [ähnliche Frage] beantwortet (http://stackoverflow.com/questions/35585310/get-nested-elements-on-xml-with-lambda-and-set-to-listobject). Mein Vorschlag ist es, '' Unterknoten '' Knoten und dann: '' in der Lage sein, sie zu bekommen. –

Antwort

1

Nun, da Sie den besten Weg dazu gefragt haben, würde ich vorschlagen, die paste special Funktion zu verwenden, die Ihr Leben unglaublich einfach macht.

Im Grunde kopieren Sie ein Beispiel Ihres xml, erstellen Sie eine Klasse mit dem Befehl paste special und deserialisieren Sie ein Objekt oder Array von Objekten mit einem xmlserializer. Es ist alles perfekt erklärt auf der MSDN-Link. Du wirst es lieben.

EDIT da Sie Probleme:

zu tun deserialisieren:

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 
} 

Die XML-Klasse:

/// <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

Danke, aber es funktioniert nicht für meine XML, die ich in Frage gestellt habe. – Zorge

+1

@Bopa Ich habe es gerade versucht und es hat perfekt funktioniert. Ich werde die Antwort aktualisieren – 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

Well ... Sie sollten Ihre XML-Struktur überdenken, weil sich File nicht innerhalb des "Gruppierungs" -Elements befindet, z. B. Files. XML-Struktur sollte wie folgt aussehen:

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

Natürlich gibt es eine Möglichkeit, dies zu umgehen, erfordert aber XDocument class + LiqToXml statt XmlDocument zu verwenden.

sehen Beispiel nehmen:

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

Ergebnis:

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

Was date Abfrage tut?

Erste select Anweisung erhält den Ordnernamen und die Liste der Dateien gehört zu diesem Ordner. Auf diese Weise:

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

Zweiter select Anweisung (SelectMany) wird über Daten und transponiert sie in Zielsuchresultates.

Versuchen Sie es!