# [C# WPF] iTunes XML sinnvoll auslesen... Wie?



## Der Maniac (2. Mai 2012)

Hallo Leute!

Ich bin gerade dabei, mir ein kleines (aber aufwändiges o.O) Programm zu bsateln, was mir die iTunes-XML Datei ausliest und die Daten anzeigen soll (Es sind bei mir ca. 36k Lieder in der XML abgelegt!)

Jetzt hänge ich aber an einem Punkt fest, undzwar wird in allen Anleitungen mit den ID-Tags, also den Attributen der einzelnen Zellen gearbeitet. Wer schonmal in die iTunes.xml geschaut hat, wird bemerkt haben, das hier keine Attribute gesetzt sind...^^

Was ich jetzt machen möchte ist folgendes:

Ich möchte die XML komplett auslesen und in eine Tabelle schreiben lassen (innerhalb des Programms) und bestimmte Zellwerte ändern, vorrangig die Interpreten und Titelnamen.

Die Frage ist jetzt nur, wie finde ich raus was in welche Zelle gehört?

Aktuell sieht die Ausgabe des Programms so aus:

22216Track ID22216NameBesser Gehts NichtArtist2raumwohnungAlbum36gradGenrePopKindMPEG-AudiodateiSize4770676Total Time213812Track Number1Year2007Date Modified2012-04-11T21:40:18ZDate Added2011-11-15T19:27:04ZBit Rate173Sample Rate44100Artwork Count2Persistent ID6047DEA566D0A794Track TypeFileLocationfile://localhost/E:/Musik/2Raumwohnung%20-%2036%20Grad/01-2raumwohnung-besser_gehts_nicht.mp3File Folder Count-1Library Folder Count-

aus diesem XML-Code:

```
<key>22216</key>
        <dict>
            <key>Track ID</key><integer>22216</integer>
            <key>Name</key><string>Besser Gehts Nicht</string>
            <key>Artist</key><string>2raumwohnung</string>
            <key>Album</key><string>36grad</string>
            <key>Genre</key><string>Pop</string>
            <key>Kind</key><string>MPEG-Audiodatei</string>
            <key>Size</key><integer>4770676</integer>
            <key>Total Time</key><integer>213812</integer>
            <key>Track Number</key><integer>1</integer>
            <key>Year</key><integer>2007</integer>
            <key>Date Modified</key><date>2012-04-11T21:40:18Z</date>
            <key>Date Added</key><date>2011-11-15T19:27:04Z</date>
            <key>Bit Rate</key><integer>173</integer>
            <key>Sample Rate</key><integer>44100</integer>
            <key>Artwork Count</key><integer>2</integer>
            <key>Persistent ID</key><string>6047DEA566D0A794</string>
            <key>Track Type</key><string>File</string>
            <key>Location</key><string>file://localhost/E:/Musik/2Raumwohnung%20-%2036%20Grad/01-2raumwohnung-besser_gehts_nicht.mp3</string>
            <key>File Folder Count</key><integer>-1</integer>
            <key>Library Folder Count</key><integer>-1</integer>
        </dict>
```

da lassen sich natürlich noch überall Leerzeichen einfügen, allerdings brauch ich die wohl weniger wenn ich die ganzen Daten in eine Tabelle packe...

Habt ihr vorschläge, wie man das am besten machen kann? Hauptsächlich die Sortierung!

Danke schonmal für das anstrengen eurer grauen Zellen!


----------



## hBGl (3. Mai 2012)

Was meinst du mit Tabelle? Datenbank?

Ich kenn mich mit WPF nicht sonderlich aus aber kannst du damit was anfangen? Reading XML with the XmlReader class - C# Tutorial


----------



## Der Maniac (4. Mai 2012)

Ne Temporäre Tabelle im Programm, also ein Array!

Das Problem bei der XML-Reader Klasse hab ich schon angesprochen... Die Klasse bezieht sich voll auf Attribute, die in der iTunes Library XML nicht vorhanden sind. Ausgelesen bekomme ich die Datei ja, es geht mir momentan "nurnoch" um die Sortierung der Daten, denn da liegt das größte Problem:

Es können bis zu 45 (glaube ich) verschiedene Datentypen angegeben werden, also Titelname, Bitrate, Speicherverbrauch, Länge, Interpret usw. Nur hat nicht jeder Titel alle Informationen, da müssen dann dementsprechend die Felder rausgesucht werden und in die ensprechenden Programmtabellenzellen geschrieben werden. Die, für die keine Daten da sind sollen leer bleiben... Klingt einfach, ist aber irgendwie krass kompliziert finde ich >_<


----------



## hBGl (4. Mai 2012)

Kannst du mir das mit dem Array genauer erklären? Wie viele Arrays und was soll darin gespeichert werden?

Wenn du für 45 Trackeigenschaften jeweils ein Array machen willst würde ich 45 if Abfragen machen ^^ was effizienteres fällt mir gerade nicht ein, bin aber auch nicht der Profi  Ich denk drüber nach, weil mich es auch intererssiert. Vielleicht kenn ich die richtigen Werkzeuge einfach noch nicht


----------



## Der Maniac (4. Mai 2012)

Das mit den if-Abfragen ist klar, anders wird es kaum gehen. Gut, man könnte sich nen "Fragenkatalog" basteln, also ne Tabelle zum abgleichen und das dann in eine for-Schleife schieben, aber bis ich da ankomme liegen noch andere Steine im Weg...^^

Das mit dem Array soll folgendermaßen laufen:

Es wird als erstes die Datei eingelesen. Anhand von 2 Daten in dieser lässt sich die Anzahl der Songs in der iTunes-Bibliothek errechnen, womit wir wissen, wieviele Spalten wir im Array brauchen (das was nach rechts läuft^^). Die Zeilen, also das Senkrechte ist ja vorgegeben durch die ganzen Informationen, die ein Titel enthalten kann. Bei meiner Bibliothek würde die Tabelle also 45 Zeilen und 36k Spalten haben. Stellt sich die Frage, wie performant das ganze dann am Ende noch ist, oder ob man doch mehrere Tabellen anlegen sollte...

Bei den If-Abfragen stoßen wir nur schon auf das nächste Problem: Wenn jetzt zufällig ein Titel als Interpret oder Titelnamen oder was auch immer einen String da stehen hat, der die Abfrage positiv ausfallen lässt, aber eigentlich ja in eine Zelle geschrieben werden soll, fällt der ganze Algorythmus in sich zusammen, weil danach alles um mindestens ein Feld verschoben ist...^^ Leicht suboptimal!

Schau dir nochmal das Beispiel oben an was ich gepostet habe. Versuch mal anhand dessen die Abfragen -mit- SIcherheitsfunktion zu erstellen. Also, so das Fehler zu 99,9% ausgeschlossen sind. Ich weiß nicht ob du dich mit der kompletten String-Klasse auskennst, aber die wird wohl doch verdammt viel Verwendung finden o.O (Substing, Contains usw.)

Da setzt ich mich morgen Abend mal dran... Nächste Woche bekomm ich noch n Buch über C# und den ganzen Kram, evtl. gibt es ja auch einen wesentlich einfacheren Weg^^


----------



## hBGl (4. Mai 2012)

Ich hab mal ein bisschen was zusammengekrikselt. Das ist natürlich von der Effizienz total schlecht (nehme ich mal an), aber es funktioniert 

Das Programm:


```
using System;
using System.Text;
using System.Xml;
using System.Collections.Generic;

namespace ParsingXml
{
    class Program
    {
        static void Main(string[] args)
        {   
            XmlDocument xmlDoc = new XmlDocument();
            /* Den Pfad musst du eventuell ändern!!! */
            xmlDoc.Load("D:/bla.xml"); // Läd das ganze XML in den Speicher
            
            XmlNode root = xmlDoc.DocumentElement; // Greift sich das erste Element
            
            if (root.HasChildNodes)
            {
                XmlNodeList tracks = root.ChildNodes; // Speichert tracks in eine Liste
                
                // Array Länge
                int arrLength = tracks.Count;
                
                // Hier wären alle Eigenschaften, die du brauchst
                // Statt string kannst du bei manchen Werten auch int nehmen oder sonstwas
                string[] trackId = new string[arrLength];
                string[] name = new string[arrLength];
                string[] duration = new string[arrLength];
                string[] bla = new string[arrLength];
                
                // Zähler
                int counter = 0;
                
                foreach (XmlNode track in tracks)
                {
                    // Alle Plätze in den Arrays belegen
                    trackId[counter] = "";
                    name[counter] = "";
                    duration[counter] = "";
                    bla[counter] = "";
                
                    if (track.HasChildNodes)
                    {
                        XmlNodeList trackVars = track.ChildNodes; // Greift sich die Eigenschaften des tracks
                        
                        for (int i = 0; i < trackVars.Count; i++)
                        {
                            if (trackVars.Item(i).Name == "key")
                            {
                                string keyVal = trackVars.Item(i).InnerText; // Speicher key Inhalt in Variable
                                
                                //
                                // Hier sind alle IF Abfragen
                                //
                                
                                if (keyVal == "Track ID")
                                {
                                    trackId[counter] = trackVars.Item(i+1).InnerText; // Speicher Inhalt der nächsten Zelle in die vorgegebene Liste
                                }
                                if (keyVal == "Name")
                                {
                                    name[counter] = trackVars.Item(i+1).InnerText;
                                }
                                if (keyVal == "Duration")
                                {
                                    duration[counter] = trackVars.Item(i+1).InnerText;
                                }
                                if (keyVal == "Bla")
                                {
                                    bla[counter] = trackVars.Item(i+1).InnerText;
                                }    
                            }
                        }
                    }
                    
                    // Zähler um eins hochzählen
                    counter++;
                }
                
                // Ausgabe aller Lieder und deren Eigenschaften
                for (int i = 0; i < trackId.Length; i++)
                {
                    Console.WriteLine("Lied " + (i+1).ToString() + ":");
                    Console.WriteLine("Track ID: " + trackId[i]);
                    Console.WriteLine("Name: " + name[i]);
                    Console.WriteLine("Laenge: " + duration[i]);
                    Console.WriteLine("Bla: " + bla[i] + "\n");
                }
            }
            else
            {
                Console.WriteLine("Keine Lieder!");
            }
            Console.ReadKey();
        }
    }
}
```
Das XML

```
<?xml version="1.0"?>
<root>
    <track>
        <key>Track ID</key><value>0123123</value>
        <key>Name</key><value>So und so</value>
        <key>Duration</key><value>3:12</value>
        <key>Bla</key><value>Hoobdy</value>
    </track>
    <track>
        <key>Track ID</key><value>164456</value>
        <key>Name</key><value>Darbn Darb</value>
    </track>
    <track>
        <key>Name</key><value>Darbn Darb</value>
        <key>Duration</key><value>0:53</value>
        <key>Bla</key><value>Zap Bra?</value>
    </track>
    <track>
        <key>Track ID</key><value>164456</value>
        <key>Duration</key><value>1:21</value>
    </track>
    <track>
    </track>
</root>
```


----------



## Der Maniac (6. Mai 2012)

Ich werde das gleich mal ausprobieren!

Die XML sieht nur ein klein wenig anders aus:


```
<dict>
        <key>22216</key>
        <dict>
            <key>Track ID</key><integer>22216</integer>
            <key>Name</key><string>Besser Gehts Nicht</string>
            <key>Artist</key><string>2raumwohnung</string>
            <key>Album</key><string>36grad</string>
            <key>Genre</key><string>Pop</string>
            <key>Kind</key><string>MPEG-Audiodatei</string>
            <key>Size</key><integer>4770676</integer>
            <key>Total Time</key><integer>213812</integer>
            <key>Track Number</key><integer>1</integer>
            <key>Year</key><integer>2007</integer>
            <key>Date Modified</key><date>2012-04-11T21:40:18Z</date>
            <key>Date Added</key><date>2011-11-15T19:27:04Z</date>
            <key>Bit Rate</key><integer>173</integer>
            <key>Sample Rate</key><integer>44100</integer>
            <key>Artwork Count</key><integer>2</integer>
            <key>Persistent ID</key><string>6047DEA566D0A794</string>
            <key>Track Type</key><string>File</string>
            <key>Location</key><string>file://localhost/E:/Musik/2Raumwohnung%20-%2036%20Grad/01-2raumwohnung-besser_gehts_nicht.mp3</string>
            <key>File Folder Count</key><integer>-1</integer>
            <key>Library Folder Count</key><integer>-1</integer>
        </dict>
</dict>
```

Weiter unten kommen dann noch Playlisten etc., da werde ich mich aber später drum kümmern. Erstmal muss der andere kram laufen!


----------



## Der Maniac (8. Mai 2012)

So, der Quellcode von dir funzt suppa, mit ein paar Anpassungen auch für die iTunes.xml! Ich habe mir jetzt nochmal nen C# Klopper von nem Kumpel besorgt und werde mich da mal durcharbeiten! Mal sehen was ich da so noch alles an wissenswertem rausholen kann!


----------



## hBGl (9. Mai 2012)

Halt mich bitte (im Thread) auf dem Laufenden, ich bin immer an effizienten Lösungen interessiert ^^


----------



## Der Maniac (9. Mai 2012)

So, ich bin grade dran beim Lesen von dem Kapitel und habe schon einige schöne Dinge gefunden, die wir verwenden könnten...

Unter anderem Fehlererkennung durch WhiteSpace-Abfragen... Das wird ein Spaß! 

Was aber ganz am Anfang des Kapitels stand: Die XML-Reader-Klasse ust gut zum auslesen und auswerten von Daten, da alles recht schnell geht (es wird nichts im Arbeitsspeicher abgelegt), zum verändern gibts da aber wohl noch was besseres... Da komme ich aber erst noch hin, mal sehen was sich da findet!

Falls du TS hast: intuxlife.de:9988
Ich bin da der [A-C-E] Maniac


----------



## Der Maniac (14. Mai 2012)

So, ich habe mich grad mal wieder drangesetzt! Abi ist jetzt ja durch^^ 

Ich hab mal ne Liste erstellt, was für Daten und Datentypen auftauchen können.
http://maniac.kilu.de/prog/iTunes_Datentypen.xlsx

Ich bin mir nicht ganz sicher, aber es kann sein das sich manche Datentypen ändern können, von daher wäre es meiner Meinung nach sinnvoll alles in Strings zu konvertieren (bis auf die beiden Datumswerte), ist ja letztendlich eh egal, da ja nur die Titel geändert werden sollen, die ja sowieso schon Strings sind. Außerdem gibt es beim konvertieren nach Strings die wenigsten Probleme^^

Bin auch grade aufm TS, also falls du lust hast! 
[A-C-E] | ZOCKERBUDE [VARIOUS - GAMING] TeamSpeak - LIVE view (#990554) - TSViewer.com [en]


Tante Edith meint:

Ich hab das Programm grad mal nach bestem Wissen abgeändert und auf eine abgespeckte Version der iTunes.xml losgelassen... Frag mich nicht wieso, aber es kommt nur Müll bei raus...^^

Er zieht sich das erste raus was er findet (was auch sonst...^^), und das ist natürlich falsch! Er muss in die dritte Ebene von <dict> reingehen, um für einen Titel Infos zu holen! Ich häng da grad irgendwie fest... Verschachtelte Schleifen, aber wie?! *kotz*

XML-File:

```
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Major Version</key><integer>1</integer>
    <key>Minor Version</key><integer>1</integer>
    <key>Date</key><date>2012-05-14T16:06:42Z</date>
    <key>Application Version</key><string>10.6.1</string>
    <key>Features</key><integer>5</integer>
    <key>Show Content Ratings</key><true/>
    <key>Music Folder</key><string>file://localhost/C:/Users/Maniac/Music/iTunes/iTunes%20Media/</string>
    <key>Library Persistent ID</key><string>67B8C11309963BCA</string>
    <key>Tracks</key>
    <dict>
        <key>22230</key>
        <dict>
            <key>Track ID</key><integer>22230</integer>
            <key>Name</key><string>Besser Gehts Nicht</string>
            <key>Artist</key><string>2raumwohnung</string>
            <key>Album Artist</key><string>2raumwohnung</string>
            <key>Composer</key><string>Testkomponist</string>
            <key>Album</key><string>36grad</string>
            <key>Grouping</key><string>Testwerk</string>
            <key>Genre</key><string>Pop</string>
            <key>Kind</key><string>MPEG-Audiodatei</string>
            <key>Size</key><integer>4770676</integer>
            <key>Total Time</key><integer>213812</integer>
            <key>Start Time</key><integer>5000</integer>
            <key>Stop Time</key><integer>210812</integer>
            <key>Disc Number</key><integer>1</integer>
            <key>Disc Count</key><integer>1</integer>
            <key>Track Number</key><integer>1</integer>
            <key>Track Count</key><integer>13</integer>
            <key>Year</key><integer>2007</integer>
            <key>BPM</key><integer>60</integer>
            <key>Date Modified</key><date>2012-05-14T16:26:45Z</date>
            <key>Date Added</key><date>2011-11-15T19:27:04Z</date>
            <key>Bit Rate</key><integer>173</integer>
            <key>Sample Rate</key><integer>44100</integer>
            <key>Part Of Gapless Album</key><true/>
            <key>Volume Adjustment</key><integer>55</integer>
            <key>Equalizer</key><string>Dance</string>
            <key>Comments</key><string>Testkommentar</string>
            <key>Rating</key><integer>60</integer>
            <key>Album Rating</key><integer>60</integer>
            <key>Album Rating Computed</key><true/>
            <key>Compilation</key><true/>
            <key>Artwork Count</key><integer>2</integer>
            <key>Series</key><string>Testsendung</string>
            <key>Season</key><integer>5</integer>
            <key>Episode</key><string>VID13</string>
            <key>Episode Order</key><integer>6</integer>
            <key>Sort Album</key><string>36grad</string>
            <key>Sort Album Artist</key><string>2raumwohnung</string>
            <key>Sort Artist</key><string>2raumwohnung</string>
            <key>Sort Composer</key><string>Testkomponist</string>
            <key>Sort Name</key><string>Besser Gehts Nicht</string>
            <key>Sort Series</key><string>Testsendung</string>
            <key>Persistent ID</key><string>6047DEA566D0A794</string>
            <key>Track Type</key><string>File</string>
            <key>Location</key><string>file://localhost/E:/Musik/2Raumwohnung%20-%2036%20Grad/01-2raumwohnung-besser_gehts_nicht.mp3</string>
            <key>File Folder Count</key><integer>-1</integer>
            <key>Library Folder Count</key><integer>-1</integer>            
        </dict>
    </dict>
</dict>
</plist>
```


----------

