Laden...

[gelöst] Xml Reader überspringt jedes zweite Element

Erstellt von Thomas B vor 8 Jahren Letzter Beitrag vor 8 Jahren 1.937 Views
T
Thomas B Themenstarter:in
223 Beiträge seit 2006
vor 8 Jahren
[gelöst] Xml Reader überspringt jedes zweite Element

Hallo,

ich habe den Xml Reader benutzt und dieser Überspringt mir jedes zweite Element. Meine Vermutung ist, dass es an dem Befehl ReadElementContentAsType() liegt und ich damit immer ein Element überspringe, wenn ich in der Schleife bei Read lande. Ich habe wegen der Übersichtlichkeit die anderen cases entfernt, sind aber alle gleich aufgebaut und schreiben nur in anderen Variablen.
Ich habe schon versucht, in der Schleife noch eine Schleife mit !EOF zu machen, sodass er das Read nicht mehr ansteuert, aber auch das hat nicht geholfen und endet mit einer Endlosschleife des Programms.

Folgende Xml Datei lese ich ein:

<?xml version="1.0"?>
<serverData noNamespaceSchemaLocation="http://s138-de.ogame.gameforge.com/api/xsd/serverData.xsd" timestamp="1459335197" serverId="de138">
  <name>Libra</name>
  <number>138</number>
  <language>de</language>
  <timezone>Europe/Berlin</timezone>
  <timezoneOffset>+02:00</timezoneOffset>
  <domain>s138-de.ogame.gameforge.com</domain>
  <version>6.1.5</version>
  <speed>5</speed>
  <speedFleet>1</speedFleet>
  <galaxies>9</galaxies>
  <systems>499</systems>
  <acs>1</acs>
  <rapidFire>1</rapidFire>
  <defToTF>0</defToTF>
  <debrisFactor>0.7</debrisFactor>
  <repairFactor>0.7</repairFactor>
  <newbieProtectionLimit>500000</newbieProtectionLimit>
  <newbieProtectionHigh>50000</newbieProtectionHigh>
  <topScore>2675996</topScore>
  <bonusFields>25</bonusFields>
  <donutGalaxy>1</donutGalaxy>
  <donutSystem>1</donutSystem>
</serverData>


 using (XmlReader Xml = XmlReader.Create(Path))
            {
                while (Xml.Read())
                {

                        if (Xml.NodeType == XmlNodeType.Element)
                        {
                            switch (Xml.Name)
                            {
                                case "number":
                                    this.mId = Xml.ReadElementContentAsInt();
                                    break;
                                case "language":
                                    this.mLanguage = Xml.ReadElementContentAsString();
                                    break;
                                case "timezone":
                                    this.mTimezone = Xml.ReadElementContentAsString();
                                    break;
                                case "timezoneOffset":
                                    this.mOffset = Xml.ReadElementContentAsString();
                                    break;
                                case "domain":
                                    this.mDomain = Xml.ReadElementContentAsString();
                                    break;
                                case "version":
                                    this.mVersion = Xml.ReadElementContentAsString();
                                    break;
                                case "speed":
                                    this.mSpeed = Xml.ReadElementContentAsInt();
                                    break;
                                case "speedFleet":
                                    this.mFleetSpeed = Xml.ReadElementContentAsInt();
                                    break;
                                case "galaxies":
                                    this.mGalaxys = Xml.ReadElementContentAsInt();
                                    break;
                                case "systems":
                                    this.Systems = Xml.ReadElementContentAsInt();
                                    break;
                                case "acs":
                                    this.mACS = Xml.ReadElementContentAsInt();
                                    break;
                                case "rapidFire":
                                    this.mRapidFire = Xml.ReadElementContentAsInt();
                                    break;
                                case "defToTF":
                                    this.mDefToTF = Xml.ReadElementContentAsInt();
                                    break;
                                case "debrisFactor":
                                    this.mDebrisFactor = Xml.ReadElementContentAsFloat();
                                    break;
                                case "repairFactor":
                                    this.mRepairFactor = Xml.ReadElementContentAsFloat();
                                    break;
                                case "newbieProtectionLimit":
                                    this.mNewbieProtectionLimit = Xml.ReadElementContentAsInt();
                                    break;
                                case "newbieProtectionHigh":
                                    this.mNewbieProtectionHigh = Xml.ReadElementContentAsInt();
                                    break;
                                case "topScore":
                                    this.mTopScore = Xml.ReadElementContentAsInt();
                                    break;
                                case "bonusFields":
                                    this.mBonusFields = Xml.ReadElementContentAsInt();
                                    break;
                                case "donutGalaxy":
                                    this.mDonutGalaxys = Xml.ReadElementContentAsInt();
                                    break;
                                case "donutSystem":
                                    this.mDonutSystems = Xml.ReadElementContentAsInt();
                                    break;
                                default:

                                    break;
                            }
                        }
                   }
            }

Gruß,
Thomas

1.029 Beiträge seit 2010
vor 8 Jahren

Hi Thomas,

ich fürchte das was du hier zeigst entspricht nicht ganz deinem Code oder deinen Daten - oder natürlich du überspringst an anderer Stelle etwas. (Hier ist ja keine Ausgabe)

Hab deinen Code mal kopiert - und bei mir wurschtelt er sich ordentlich durch jeden einzelnen Node durch. (Man muss hier allerdings fairerweise anmerken, dass du nur ein einziges Mal "Xml.ReadElementContentAsInt();" aufrufst, da es eben nur ein "number"-Element gibt und deine switch-Anweisung ja alles andere übergeht.

Warum du das ganze so löst verstehe ich allerdings nicht ganz. Der Xml-Datei liegt ein Schema zu Grunde (http://s138-de.ogame.gameforge.com/api/xsd/serverData.xsd) - dieses Schema kann man mit xsd.exe oder einem Online-Generator in eine C#-Klasse wandeln. (z.B. http://www.httputility.net/xsd-to-csharp-vb-class.aspx)

Und um das ganze dann einzulesen kannst du einfach Deserialisieren von dem Xml-File und bekommst dann direkt eine fertige Instanz der so generierten Klasse.

Erklärt unter: https://msdn.microsoft.com/en-us/library/fa420a9y(v=vs.110).aspx

LG

T
Thomas B Themenstarter:in
223 Beiträge seit 2006
vor 8 Jahren

Hallo Taipi88,

Danke für deine Antwort. Den vor dir vorgestellten Ansatz über einen Generator kannte ich so noch nicht.

Also die Ausgabe sieht so aus an andere Stelle:


this.richTextBox1.Text = GS.Id.ToString() + System.Environment.NewLine;
            this.richTextBox1.Text += GS.Language.ToString() + System.Environment.NewLine;
            this.richTextBox1.Text += GS.Timezone.ToString() + System.Environment.NewLine;
            this.richTextBox1.Text += GS.Offset.ToString() + System.Environment.NewLine;
            this.richTextBox1.Text += GS.Domain.ToString() + System.Environment.NewLine;
            this.richTextBox1.Text += GS.Version.ToString() + System.Environment.NewLine;
            this.richTextBox1.Text += GS.Speed.ToString() + System.Environment.NewLine;
            this.richTextBox1.Text += GS.FleetSpeed.ToString() + System.Environment.NewLine;
            this.richTextBox1.Text += GS.Galaxys.ToString() + System.Environment.NewLine;
            this.richTextBox1.Text += GS.Systems.ToString() + System.Environment.NewLine;
            this.richTextBox1.Text += GS.ACS.ToString() + System.Environment.NewLine;
            this.richTextBox1.Text += GS.RapidFire.ToString() + System.Environment.NewLine;
            this.richTextBox1.Text += GS.DefToTF.ToString() + System.Environment.NewLine;
            this.richTextBox1.Text += GS.DebrisFactor.ToString() + System.Environment.NewLine;
            this.richTextBox1.Text += GS.RepairFactor.ToString() + System.Environment.NewLine;
            this.richTextBox1.Text += GS.NewbieProtectionLimit.ToString() + System.Environment.NewLine;
            this.richTextBox1.Text += GS.NewbieProtectionHigh.ToString() + System.Environment.NewLine;
            this.richTextBox1.Text += GS.TopScore.ToString() + System.Environment.NewLine;
            this.richTextBox1.Text += GS.BonusFields.ToString() + System.Environment.NewLine;
            this.richTextBox1.Text += GS.DonutGalaxys.ToString() + System.Environment.NewLine;
            this.richTextBox1.Text += GS.DonutSystems.ToString() + System.Environment.NewLine;

Die Werte setze ich vorher auf "" oder 0 und sehe Sie auch in der Textbox, wo der Wert nicht ausgelesen wurde (jedes zweite Element).

Ich habe oben den vollständigen switch Block reingepostet.

Gruß,
Thomas

16.806 Beiträge seit 2008
vor 8 Jahren

Du liest hier zwei Mal.
Einmal bei Read und einmal bei ReadAsXY.

Du verwendest den "Enumerator" falsch.
Schau Dir in der Doku an, wie es richtig geht.

In Deinem Fall Xml.Value und dann Parsen.

T
Thomas B Themenstarter:in
223 Beiträge seit 2006
vor 8 Jahren

Hi Abt,

Jetzt komme ich aber nicht an den Wert ran. Ich habe nun folgendes versucht:


if (Xml.NodeType == XmlNodeType.Element)
                    {
                        switch (Xml.Name)
                        {
                            case "number":
                                Xml.MoveToContent();
                                this.mId = Convert.ToInt32(Xml.Value);
                                break;
                        }
                    }

Der Wert von Value ist leer an dieser Stelle, weil er vermutlich noch im Type Node ist und nicht in den Content wechseln kann. Die Doku geht auf die Konstellation wie ich sie habe nicht ein, da es keine Schleife verwendet, weil es nur ein Buch einliest.

Ich könnte es wie in dem Beispiel machen, und alles in Folge einlesen (so wie bei title), bin dann aber an die Reihenfolge in der Datei gebunden.

Gruß,
Thomas

16.806 Beiträge seit 2008
vor 8 Jahren

Na, dann musste das eben abfangen.
Was anderes macht die ReadElementContentAsInt-Methode auch nicht.

Du brauchst auch kein MoveToContent.
Hab Dir doch Xml.Value gesagt.

Ich seh in der Doku ne Schleife...

   // Parse the file and display each of the nodes.
        while (reader.Read())
        {
            switch (reader.NodeType)
            {

wobei die Schleife eh irrelevant ist.

T
Thomas B Themenstarter:in
223 Beiträge seit 2006
vor 8 Jahren

Hey,

ich habe es nun wie folgt gelöst:


using (XmlReader Xml = XmlReader.Create(Path))
{
           Xml.ReadToFollowing("number");
           this.mId = Xml.ReadElementContentAsInt();
           this.mLanguage = Xml.ReadElementContentAsString();
           this.mTimezone = Xml.ReadElementContentAsString();
...

Wird natürlich blöd, sollte die Datei verändert werden, funktioniert aber erstmal wie es soll und wird bei Bedarf später verbessert. Danke für die Unterstützung.

Gruß,
Thomas

5.299 Beiträge seit 2008
vor 8 Jahren

und nun geh nochmal dem in Post#2 gesagten gründlich nach.
Die ganze Xml-Wurstelei ist nämlich überflüssig, wenn das dort gesagte zutrifft, und man sich einfach einen Satz Xml-Serialisierbarer Klassen generieren lassen kann.
Und wenn dem so ist, ist das rückspeicher-Problem damit auch abgehandelt - Serialisierung ist bidirektional.

Der frühe Apfel fängt den Wurm.