[C#][gelöst] XML in Schleife auslesen

Cyperfriend

Der ohne Avatar
Registriert
14 Juli 2013
Beiträge
1.123
Ich habe eine XML-Datei, die ich gerne mit einer Schleife auslesen würde. Das Programm scheint zu erkennen, wie viele Einträge auszulesen wären, zeigt mir aber dann immer nur den ersten Eintrag an. Hier der Code und ein Bild. Hoffe jemand kann mir sagen, was ich falsch mache.

C#
[src=csharp]
{
// Dokument laden
XmlDocument doc = new XmlDocument();
doc.Load(pfad);

XmlElement root = doc.DocumentElement;

foreach (XmlNode vorname in root.ChildNodes)
{
XmlNode nodeVorname = doc.SelectSingleNode("/Personen/Person/Vorname");
XmlNode nodeNachname = doc.SelectSingleNode("/Personen/Person/Nachname");
XmlNode nodeGeburtstag = doc.SelectSingleNode("/Personen/Person/Geburtstag");
comboBox1.Items.Add(nodeVorname.InnerText + " " + nodeNachname.InnerText + "\n");
}
}
[/src]

XML
[src=xml]
<Personen>
<Person>
<Nachname>Max</Nachname>
<Vorname>Mustermann</Vorname>
<Alter>10</Alter>
</Person>
<Person>
<Nachname>Maxi</Nachname>
<Vorname>Maxi</Vorname>
<Alter>15</Alter>
</Person>
</Personen>
[/src]

Anhang anzeigen 34100
 
Zuletzt bearbeitet:
Re: [C#] XML in Schleife auslesen

Du hast bei dem Beispiel einen kleinen Denkfehler:

Deine Foreach iteriert über jede Person drüber. Soweit so gut. Aber: Du gehst dann mittels SelectSingleNode vom Root-Knoten aus. SelectSingleNode dürfte, allen Anschein nach, dann immer das erste gefundene Element auswählen, auch wenn mehrere zur Verfügung stehen.

Womit du dir helfen kannst sind folgende Änderungen:

1) Naming von XmlNode vorname überarbeiten - is ja schließlich eine Person die du auslesen willst ;)
2) person["Vorname"].InnerText + person["Nachname"].InnerText liefert dir dann den entsprechend zusammengesetzten Namen. Du kannst zwar auch wieder drüber iterieren mittels person.ChildNodes aber davon würd ich dir abraten. Schließlich willst du ja das Alter nicht auslesen ;)

Quelle als Beispiel:
 
Zuletzt bearbeitet:
  • Thread Starter Thread Starter
  • #3
Re: [C#] XML in Schleife auslesen

Blicks nicht :( Was meinst du?
 
Re: [C#] XML in Schleife auslesen

Probier mal folgenden Code aus, ist etwas überarbeitet. ".//Vorname" geht vom ausgewählten Knoten aus, "//Vorname" würde vom Root aus gehen (lt. Top-Antwort von )

[src=csharp]
foreach (XmlNode person in root.ChildNodes)
{
XmlNode nodeVorname = person.SelectSingleNode(".//Vorname");
XmlNode nodeNachname = person.SelectSingleNode(".//Nachname");
XmlNode nodeGeburtstag = person.SelectSingleNode(".//Geburtstag");
comboBox1.Items.Add(nodeVorname.InnerText + " " + nodeNachname.InnerText + "\n");
}
[/src]
 
Re: [C#] XML in Schleife auslesen

Um das Problem nochmal genau zu erklären.

[src=csharp]
{
// Dokument laden
XmlDocument doc = new XmlDocument();
doc.Load(pfad);

XmlElement root = doc.DocumentElement;

foreach (XmlNode vorname in root.ChildNodes)
{
}
}
[/src]

Mit dem Code durchläufst du jedes Element eines Containers (beispielsweise Liste o. Ä.). Das ist quasi nur eine verkürzte For-Schleife; im Endeffekt bekommst du pro Objekt im Container eine Referenz, auf die der Code angewandt wird. Das ist eine saubere und gut lesbare Vorgehensweise, solange man keinen Zugriff auf den Index des Objekts braucht - brauchst du hier nicht, ist also alles gut.

[src=csharp]
foreach (XmlNode vorname in root.ChildNodes)
{
XmlNode nodeVorname = doc.SelectSingleNode("/Personen/Person/Vorname");
XmlNode nodeNachname = doc.SelectSingleNode("/Personen/Person/Nachname");
XmlNode nodeGeburtstag = doc.SelectSingleNode("/Personen/Person/Geburtstag");
comboBox1.Items.Add(nodeVorname.InnerText + " " + nodeNachname.InnerText + "\n");
}
[/src]

Hier ist aber dann das Problem. Die Foreach-Schleife gibt dir jeweils eine Referenz auf die direkten Kinder des obersten Knotens, da du root auf den Dokument-Knoten festgelegt hast. Du bekommst also Zugriff auf die Knoten Person und Person (den ersten und den zweiten Knoten mit dem Namen):

[src=xml]
<Personen>
<Person>
<Nachname>Max</Nachname>
<Vorname>Mustermann</Vorname>
<Alter>10</Alter>
</Person>
<Person>
<Nachname>Maxi</Nachname>
<Vorname>Maxi</Vorname>
<Alter>15</Alter>
</Person>
</Personen>
[/src]

Mit dieser Referenz fängst du aber gar nichts an! Du müsstest normalerweise jetzt von diesem Knoten ausgehen, das tust du aber nicht. Du holst dir immer nur einen Knoten aus dem Dokument selbst, ohne dabei irgendwie die Möglichkeit zu haben, auf spätere Knoten zuzugreifen.
Wenn wir uns deinen Code nämlich einmal genau anschauen:

[src=csharp]
XmlNode nodeVorname = doc.SelectSingleNode("/Personen/Person/Vorname");
XmlNode nodeNachname = doc.SelectSingleNode("/Personen/Person/Nachname");
XmlNode nodeGeburtstag = doc.SelectSingleNode("/Personen/Person/Geburtstag");
[/src]

Sehen wir, dass du immer vom Objekt doc aus den ersten Knoten, der deiner Beschreibung entspricht, nimmst. Das ist aber immer derselbe, wieso sollte sich das ändern?

Im Endeffekt ist das zu fixen ganz einfach. Das hat dir Larius ja auch gezeigt - anstatt vom Dokumentknoten auszugehen, liest du immer das erste Kind des aktuell durch die Foreach-Schleife ausgewählten Knotens aus. Das ist beim ersten Schleifendurchlauf die Person mit dem Namen Mustermann Max, beim zweiten die Person mit dem Namen Maxi Maxi. Diesmal greifst du aber auch tatsächlich auf diese Personen zu, und nicht immer nur auf den Dokument-Knoten, und damit auf die erste Person.
 
  • Thread Starter Thread Starter
  • #6
Re: [C#] XML in Schleife auslesen

Danke für die Erklärung. Jetzt ist es logisch.
 
  • Thread Starter Thread Starter
  • #7
Re: [C#] XML in Schleife auslesen

Ich hänge die Frage einfach mal hier an, auch wenn die eigentliche Frage schon beantwortet ist:

Wenn ich nun eine Person ausgelesen habe, wie kann ich dann das entsprechende Alter irgendwo auf der Form anzeigen lassen?

Außerdem würde ich die Einträge gerne mit IDs versehen, aber ich habe keine Ahnung, wie ich das machen kann. Das XML sollte dann am Ende so aussehen, damit ich später auch weitere Einträge gezielt ansprechen kann. Wäre dann ja auch wichtig, wenn man was ändern oder löschen oder hinzufügen möchte.
[src=xml]
<Personen>
<Person id=1>
<Nachname>Max</Nachname>
<Vorname>Mustermann</Vorname>
<Alter>10</Alter>
</Person>
<Person id=2>
<Nachname>Maxi</Nachname>
<Vorname>Maxi</Vorname>
<Alter>15</Alter>
</Person>
</Personen>
[/src]
 
[src=xml]
<Personen>
<Person id="1">
<Vorname>Max></Vorname>
</Person
<Person id="2">
<Vorname>Moritz></Vorname>
</Person>
</Personen>
[/src]

Stark vereinfachtes XML. Mit Anführungszeichen kannst du ein Attribut zu einem XML Element hinzufügen.

Mittels:

[src=csharp]
XmlNode person = doc.SelectNodes("/Names/Name[@id='" + ID + "']");
[/src]

holst du dir dann das entsprechende Element und kannst dann, so wie du bereits den Namen ausgelesen hast, auch auf das Alter zugreifen.

Also einfach

[src=csharp]
XmlNode person = doc.SelectNodes("/Names/Name[@id='" + ID + "']");
String Alter = person.SelectSingleNode(".//Alter").InnerText;
[/src]

und schon kannst du, entsprechend dem Wert der ID, das Alter einer gewünschten Person in einen String auslesen und dann weiterverwenden ;)
 
[src=vb]
doc.Load("filename.xml")
Dim xmlTitles As Xml.XmlNodeList = doc.GetElementsByTagName("Alter")
For i As Integer = 0 To xmlTitles.Count - 1
CheckedListBox1.Items.Add(xmlTitles(i).FirstChild.Value)
Next[/src]


Muss sicher modifiziert werden, da ich mir lediglich die Emailadressen in eine Checkedlistbox ausgeben lasse.
 
  • Thread Starter Thread Starter
  • #10
Ich habe das von Larius versucht (Mit VB kann ich nichts anfangen), aber hat natürlich nicht geklappt. Visual Studio stört sich daran, dass ID nirgends festgelegt wird und ich weis nicht, wie ich die richtig festlegen soll.

Außerdem bräuchte ich noch eine Lösung, wie man die ID mittels Programm in die XML bekommt. Manuell nachtragen ist ja nicht so das Wahre.
 
Bei einer so aufgebauten XML-Datei:

[src=xml]
<Personen>
<Person>
<Nachname>Max</Nachname>
<Vorname>Mustermann</Vorname>
<Alter>10</Alter>
</Person>
<Person>
<Nachname>Maxi</Nachname>
<Vorname>Maxi</Vorname>
<Alter>15</Alter>
</Person>
</Personen>
[/src]

Würde ich so vorgehen (wenn du jetzt alle Vornamen zu einer Liste packen willst):

[src=csharp]
{
List<String> personList = new List<String>();

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

XmlElement root = doc.DocumentElement;

foreach(XmlNode person in root.ChildNodes) {
personList.add(person["vorname"] + " " + person["nachname"] + ", " + person["alter"]);
}
}
[/src]

Wenn du dir die Liste ausgeben lässt, sollte das ganze so aussehen:

Mustermann Max, 10
Maxi Maxi, 15

Theoretisch musst du also keine IDs festlegen. Das ganze ist aber natürlich nötig, wenn irgendwann Dopplungen auftreten können. Falls du das willst und eine Referenz auf deinen Node hast, kannst du einfach über SetAttribute gehen:

[src=csharp]node.SetAttribute("id", 15);[/src]

Würde bei dem Node node das Attribut id auf 15 setzen.
 
Zurück
Oben