XML Importieren (Schutz vor Fehler)

  • VB.NET
  • .NET (FX) 4.5–4.8

Es gibt 5 Antworten in diesem Thema. Der letzte Beitrag () ist von petaod.

    XML Importieren (Schutz vor Fehler)

    Hallo ihr lieben, ich hoffe jemand kann mir helfen. Es geht um folgendes.
    Zum HIntergrund, ich habe ein kleines Programm in VB.net geschrieben, mit dem zum größten Teil eingetragene Werte von NumUpDown oder Checkboxen in Dictionarys gespeichert werden.
    Diese werden dann bei Bedarf über eine XML Dataset in eine XML Datei geschrieben und können dann wieder auf gleichem Weg von XML > Dataset in die Dictionarys > Controls geladen werden.

    Die Datatables habe ich über die Toolbox hinzugefügt, sie Taucht also im Projekt Explorer nicht auf, wohl aber unter dem Hauptframe und per Eigenschaften, habe ich die nötigen Einträge schon hinzugefügt. (Es passiert also nicht mehr bei der Laufzeit). Jede Table ist für ein Dictionary zuständig ,und die Einträge sind Entweder Decimal oder Boolean und haben den Wert "Attribute". Die Dictionarys werden auch beim Programmstart ("Keys" erstellt). Lediglich die Values (Einstellungen der Controls) werden dort dann per Code eingetragen.

    So speichere ich die Dic in die Tables:

    VB.NET-Quellcode

    1. Sub Speichern()
    2. Dim SFD As New SaveFileDialog With {
    3. .Filter = "*.xml|*.xml"
    4. }
    5. If SFD.ShowDialog = Windows.Forms.DialogResult.Cancel Then
    6. Exit Sub
    7. End If
    8. EntariaShip.XMLDataset.Clear()
    9. EntariaShip.XMLDataset.Tables("Datei").Rows.Add(New Object() {"Ja", My.Settings.Version})
    10. EntariaShip.XMLDataset.Tables("Antriebe").Rows.Add(New Object() _
    11. {My.Settings.AntriebsBEW, 'Bewegungspunkte
    12. My.Settings.AntriebsPreisMulti, 'Preismultiplikator
    13. My.Settings.AntriebsSteigerMulti, 'Steigerungs Preismultiplikator
    14. My.Settings.AntriebsSteigerung, 'gekaufte Steigerung
    15. My.Settings.AntriebsTyp, 'Antriebstyp
    16. My.Settings.AntriebsWarpSteigerung, 'gekaufte Warpsteigerung
    17. My.Settings.Warp}) 'effektive Warpstufe
    18. EntariaShip.XMLDataset.Tables("Spezielles").Rows.Add(New Object() _
    19. {EntariaShip.DicSpezielles("Gastank"),
    20. EntariaShip.DicSpezielles("Raumfaltsprunktank"),
    21. EntariaShip.DicSpezielles("Sprungdüsen"),
    22. EntariaShip.DicSpeziellesBool("Booster"),
    23. EntariaShip.DicSpeziellesBool("Cyberlink"),
    24. EntariaShip.DicSpeziellesBool("Fusionsgenerator"),
    25. EntariaShip.DicSpeziellesBool("GelKonverter"),
    26. EntariaShip.DicSpeziellesBool("Luftschiff"),
    27. EntariaShip.DicSpeziellesBool("MAMReaktor"),
    28. EntariaShip.DicSpeziellesBool("Mecharme"),
    29. EntariaShip.DicSpeziellesBool("Motorradbeiwagen"),
    30. EntariaShip.DicSpeziellesBool("Raumfaltantrieb"),
    31. EntariaShip.DicSpeziellesBool("Schwerkraft-Generator"),
    32. EntariaShip.DicSpeziellesBool("Vektorschubkontrolle")})
    33. EntariaShip.XMLDataset.WriteXml(SFD.FileName, XmlWriteMode.IgnoreSchema)
    34. End Sub

    Es sind noch weitere Tables, aber ich denke es zeigt, wie ich sie speichere. in der XML Datei sieht man sie dann so.

    XML-Quellcode

    1. <?xml version="1.0" standalone="yes"?>
    2. <EntariaShipDatenbank>
    3. <Datei EntariaSchiff="Ja" Version="0.0.8" />
    4. <Antriebe AntriebsBEW="16" AntriebsPreisMulti="10000" AntriebsSteigerMulti="1000" AntriebsSteigerung="0" AntriebsTyp="Antigrav-System" AntriebsWarpSteigerung="2" Warp="3" />
    5. <Spezielles Gastank="1" Raumfaltsprunktank="1" Sprungdüsen="0" Booster="false" Cyberlink="false" Fusionsgenerator="true" GelKonverter="false" Luftschiff="false" MAMReaktor="true" Mecharme="false" Motorradbeiwagen="false" Raumfaltantrieb="true" Schwerkraft-Generator="true" Vektorschubkontrolle="false" />
    6. </EntariaShipDatenbank>


    Das Laden der XML mache ich so. (Und prüfe ob der Eintrag "Ja" an nötiger Stelle ist, um zumindest davon ausgehen zu können, das man versucht die richtige XML zu laden.)

    VB.NET-Quellcode

    1. Sub Laden()
    2. Dim OFD As New OpenFileDialog With {
    3. .Filter = "*.xml|*.xml"
    4. }
    5. EntariaShip.XMLDataset.Clear()
    6. If OFD.ShowDialog = Windows.Forms.DialogResult.Cancel Then
    7. Exit Sub
    8. Else
    9. EntariaShip.XMLDataset.ReadXml(OFD.FileName)
    10. If Not EntariaShip.XMLDataset.Tables("Datei").Rows(0)("EntariaSchiff").ToString = "Ja" Then
    11. MessageBox.Show("Falsche Datei")
    12. Exit Sub
    13. Else
    14. MessageBox.Show("Gut")
    15. End If
    16. End If
    17. For Reinladen = 1 To 10
    18. Select Case Reinladen
    19. Case Is = 1 'Antriebe
    20. Dim DS = EntariaShip.XMLDataset.Tables("Antriebe")
    21. With My.Settings
    22. .AntriebsBEW = CInt(DS.Rows(0)("AntriebsBEW"))
    23. .AntriebsPreisMulti = CInt(DS.Rows(0)("AntriebsPreisMulti"))
    24. .AntriebsSteigerMulti = CInt(DS.Rows(0)("AntriebsSteigerMulti"))
    25. .AntriebsSteigerung = CInt(DS.Rows(0)("AntriebsSteigerung"))
    26. .AntriebsTyp = DS.Rows(0)("AntriebsTyp").ToString
    27. .AntriebsWarpSteigerung = CInt(DS.Rows(0)("AntriebsWarpSteigerung"))
    28. .Warp = CInt(DS.Rows(0)("Warp"))
    29. End With
    30. Case Is = 2 'Spezielles
    31. Dim DS = EntariaShip.XMLDataset.Tables("Spezielles")
    32. Dim Dic As Dictionary(Of String, Decimal) = EntariaShip.DicSpezielles
    33. Dim DicBool As Dictionary(Of String, Boolean) = EntariaShip.DicSpeziellesBool
    34. Dicimport2(DS, Dic, DicBool)
    35. Case Is = 3 'Mannschaft
    36. Dim DS = EntariaShip.XMLDataset.Tables("Mannschaft")
    37. Dim Dic As Dictionary(Of String, Decimal) = EntariaShip.DicMannschaft
    38. Dicimport(DS, Dic)
    39. End Select
    40. Next
    41. End Sub
    42. Sub Dicimport(ByVal DS As DataTable, ByRef Dic As Dictionary(Of String, Decimal))
    43. For Each dr As DataColumn In DS.Columns
    44. If Dic.ContainsKey(dr.ColumnName) Then
    45. Dic(dr.ColumnName) = CDec(DS.Rows(0)(dr))
    46. Else
    47. MessageBox.Show("Der Eintrag: " & dr.ColumnName & " existiert in dieser Version leider nicht mehr!")
    48. End If
    49. Next
    50. End Sub
    51. Sub Dicimport2(ByVal DS As DataTable, ByRef Dic As Dictionary(Of String, Decimal), ByRef DicBool As Dictionary(Of String, Boolean))
    52. For Each dr As DataColumn In DS.Columns
    53. If DS.Rows(0)(dr).GetType() = GetType(Decimal) Then
    54. If Dic.ContainsKey(dr.ColumnName) Then
    55. Dic(dr.ColumnName) = CDec(DS.Rows(0)(dr))
    56. Else
    57. MessageBox.Show("Der Eintrag: " & dr.ColumnName & " existiert in dieser Version leider nicht mehr!")
    58. End If
    59. Else
    60. If DicBool.ContainsKey(dr.ColumnName) Then
    61. DicBool(dr.ColumnName) = CBool(DS.Rows(0)(dr))
    62. Else
    63. MessageBox.Show("Der Eintrag: " & dr.ColumnName & " existiert in dieser Version leider nicht mehr!")
    64. End If
    65. End If
    66. Next
    67. End Sub

    Die Subs "Dicimport" und "Dicimport2" sollten für die Decimal bzw Boolean sein. Eigtl. sollte auch mit diesen Subs geschaut werden, ob er Key den ich aus der XML Importiere noch in den Dic`s existiert, bevor ich die reinschreibe, das klappt zumindest, oder es kommt kein Fehler..

    Nun zum Problem:
    Ich schätze die beiden Import Subs, haben kaum den richtige Code, um 2 bestimmte Szenarios abzudecken
    1.) Der Eintrag in der XML Datei gibt es nicht mehr im Tool (Dicionarys / Dataset)
    2.) Es fehlt ein EIntrag in der XML Datei, weil sie älter ist und es diesen noch nicht gab.

    Ich hoffe, da ich meinen zugegeben miesen Code .. offen lege, das mir jemand da helfen mag wie ich das abfange. Also Eintrag in der XML zu wenig oder zu viel, Nachricht ausgeben und übergehen. Wenn alles ok ist, den Wert in das passende Dic schreiben.

    EDIT

    Habe den Code hinzugefügt,
    In dem Case stehen wirklich nur noch weitere Dics die so aufgebaut sind, wie "Spezielles" wollte den Beitrag nicht so voll werden lassen, sah so schon zu viel aus..

    Case 3 Mannschaft dass man sieht wie der Code aussieht (Er ruft die Import auf für Decimal)
    End Select
    Next
    End Sub

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „Black-Mage“ ()

    Achtung, keine Problemlösung folgend.
    Klingt, als ob das Problem kräftig auf Folgendes eingedampft werden könnte: Wie überprüft man, ob das Schema einer XML geändert wurde. Daraus ergeben sich super Suchbegriffe bei einer Suchmaschine.

    Kleine Anmerkung zu Deinem Code: Es ergibt sich eine inhaltliche Lücke zwischen Zeile#41 und #42. Damit ist der Code unvollständig inkonsistent. Und das wird ungern im Forum gesehen. Weil man dann ganz schnell bei folgenden Gespräch ist:
    • A: Ich versteh nicht, warum das nicht geht.
    • B: Dann mach es doch mit einem Schnargl.
    • A: Den hab ich schon eingebaut, den Code hab ich aber einfach mal hier weggelassen, hab ich nicht für wichtig empfunden.
    • B: Aber der Schnargl ist für die richtige Funktionsweise absolut wichtig!
    • A: In Zeile 573 steht ja doch was über den Schnargl.
    • B: Aber nicht alles.
    • A: Ist doch nicht so wichtig. Aber hier, bitte.
    • B: Der Schnargl wird ja komplett falsch initialisiert. Kein Wunder, dass das nichts wird. Wenn der nicht mit 42 gefüttert wird, schnurpst der Schnargl falsch. Die Initialisierung gehört in Post 1! Dann können wir ja hier ewig Rätsel raten!
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.

    VaporiZed schrieb:

    Achtung, keine Problemlösung folgend.
    Klingt, als ob das Problem kräftig auf Folgendes eingedampft werden könnte: Wie überprüft man, ob das Schema einer XML geändert wurde. Daraus ergeben sich super Suchbegriffe bei einer Suchmaschine.

    Kleine…


    Zuerst danke für die Antwort und das aufmerksam machen meines Fehlers. Habe den Code ergänzt. Sollte es trotzdem gewünscht sein, das ich alles Poste auch wenn es nur weitere Dic`s sind, gleicher Code andere Namen, dann mach ich das natürlich.

    Ich schau, ob ich etwas dazu finde bei google. Und melde mich nochmal.

    Es ging bei den Änderungen in der XML eher darum das es eine ältere XML Version ist und dort einfach Einträge fehlen, oder noch drin stehen, obgleich sie nicht mehr benutzt werden. Und weniger ob man daran was editiert. Aber ich suche trotzdem und melde melde mch hier. :)

    Black-Mage schrieb:

    Es ging bei den Änderungen in der XML eher darum das es eine ältere XML Version ist und dort einfach Einträge fehlen,
    Wenn du die XML in eine passende Objektstruktur deserialisierst, brauchst du dir darüber keine Gedanken machen.
    Obsolete Einträge werden dann automatisch weg gelassen und fehlende mit Default-Werten eingetragen.
    Dann die Objektstruktur einfach an dein Dataset binden und der Code wird wesentlich übersichtlicher.
    --
    If Not Program.isWorking Then Code.Debug Else Code.DoNotTouch
    --

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „petaod“ ()

    Danke für den Denkanstoß in die richtige Richtung.

    Nur kurz zur Klarstellung, weil das von Dir verwendete Zitat m.E. etwas in Widerspruch zu Deiner Aussage steht, @petaod.
    • XML enthält 10 Einträge, davon 2 veraltete -> beim Deserialisieren werden diese einfach ignoriert. Das sagtest Du bereits. Ich erwähne es, weil Dein Zitat eine andere Annahme macht, und zwar die folgende:
    • XML enthält 10 Einträge, aktuelles Objekt aber 12 -> Diese können durch Festlegung von DataRow-DefaultValues quasi ausgeglichen werden. Wenn in der XML kein Wert drinsteht, wird der Default-Value hergenommen.
    Letzteres kann auch ein <DbNull> oder Nothing sein. Dieses kannst Du leicht finden und dann Dich darum kümmern. Damit ist leider noch nicht geklärt, wie man Punkt 1 erkennen kann. Aber ist schon mal ein Schritt in die richtige Richtung.

    ##########

    Ah, Dein Edit und mein Post kamen zeitgleich.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „VaporiZed“ ()

    Ja, ich hab's selber gemerkt, dass meine Aussage nicht beide Fälle abdeckt und hab's korrigiert.
    Alte XML-Einträge werden ignoriert, fehlende durch Default-Werte abgedeckt.
    Ob das fachlich noch angepasst werden muss, kann natürlich nur mit mehr Information entschieden werden.
    --
    If Not Program.isWorking Then Code.Debug Else Code.DoNotTouch
    --