Problem mit Dataset ReadXML - Tabelle neuer Eintrag - WriteXML

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

Es gibt 18 Antworten in diesem Thema. Der letzte Beitrag () ist von seelenreiter.

    Problem mit Dataset ReadXML - Tabelle neuer Eintrag - WriteXML

    Hallo zusammen,

    ich habe da ein Problem mit einer XML Datei. Ich habe das jetzt mal exemplarisch erstellt:

    XML-Quellcode

    1. <?xml version="1.0" encoding="UTF-8"?>
    2. <Hauptebene>
    3. <Spalte1>Bonn</Spalte1>
    4. <Spalte2>Hamburg</Spalte2>
    5. <Tabelle1>
    6. <Spalte1>Elbe</Spalte1>
    7. <Spalte2>Weser</Spalte2>
    8. </Tabelle1>
    9. <Tabelle1>
    10. <Spalte1>Rhein</Spalte1>
    11. <Spalte2>Mosel</Spalte2>
    12. </Tabelle1>
    13. </Hauptebene>


    Diese XML lade ich nun in ein Dataset.

    VB.NET-Quellcode

    1. DSet.ReadXml("data.xml")


    Jetzt kann ich ja im Dataset die Tabelle Tabelle1 ansprechen und z.B. in ein DataGridView verweisen.

    VB.NET-Quellcode

    1. DGV_Tabelle1.DataSource = DSet
    2. DGV_Tabelle1.DataMember = DSet.Tables("Tabelle1").TableName.ToString


    Füge ich eine Zeile im DataGridView ein und speichere das Dataset wieder ab,

    VB.NET-Quellcode

    1. Dim stream As New System.IO.FileStream("data.out.xml", System.IO.FileMode.Create)
    2. DSet.WriteXml(stream)
    3. stream.Dispose()



    wird die neue Zeile in der XML an die falsche Stelle geschrieben.

    XML-Quellcode

    1. <?xml version="1.0" encoding="UTF-8"?>
    2. <Hauptebene>
    3. <Spalte1>Bonn</Spalte1>
    4. <Spalte2>Hamburg</Spalte2>
    5. <Tabelle1>
    6. <Spalte1>Elbe</Spalte1>
    7. <Spalte2>Weser</Spalte2>
    8. </Tabelle1>
    9. <Tabelle1>
    10. <Spalte1>Rhein</Spalte1>
    11. <Spalte2>Mosel</Spalte2>
    12. </Tabelle1>
    13. </Hauptebene>
    14. <Tabelle1>
    15. <Spalte1>Donau</Spalte1>
    16. <Spalte2>Isar</Spalte2>
    17. </Tabelle1>


    Versucht man jetzt die Datei erneut einzulesen, kommt eine Fehlermeldung.

    Ein Ausnahmefehler des Typs "System.Xml.XmlException" ist in System.Xml.dll aufgetreten.

    Zusätzliche Informationen: Es sind mehrere Stammelemente vorhanden. Zeile 19, Position 2.


    Mache ich da beim Speichern einen Fehler?

    bzw. Wie bekomme ich die Ergänzung an die richtige Stelle?

    Viele Grüße
    Ingo
    Da freut sich @ErfinderDesRades: Untypisierte DataSet-Zugriffe wie "DSet.Tables("Tabelle1")"
    Was hindert Dich daran, typisiert zu arbeiten? Macht die Sache deutlich leichter.
    @seelenreiter: hier geht's zu den vier Views, ein sehr gutes Tutorial vom EdR.

    Spekulatius:
    Für das Programm wird nach dem Laden in der XML wohl nur eine Tabelle zu finden sein, nämlich "Hauptebene". Das sich darin ein Objekt namens "Tabelle1" befindet, wird erstmal ignoriert.
    Wenn Du dann untypisiert über den Tabellennamen zugreifst, wird wohl festgestellt, dass es keine Tabelle1 gibt. Und es wird eine neue Tabelle erstellt. Neben der bestehenden namens "Hauptebene". Und so wird es dann auch abgespeichert.
    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“ ()

    Ok, ich habe die XML eingelesen und dann das Schema gespeichert.

    XML-Quellcode

    1. <?xml version="1.0"?>
    2. <xs:schema id="NewDataSet" xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
    3. <xs:element name="Hauptebene">
    4. <xs:complexType>
    5. <xs:sequence>
    6. <xs:element name="Spalte1" type="xs:string" minOccurs="0" />
    7. <xs:element name="Spalte2" type="xs:string" minOccurs="0" />
    8. <xs:element name="Tabelle1" minOccurs="0" maxOccurs="unbounded">
    9. <xs:complexType>
    10. <xs:sequence>
    11. <xs:element name="Spalte1" type="xs:string" minOccurs="0" />
    12. <xs:element name="Spalte2" type="xs:string" minOccurs="0" />
    13. </xs:sequence>
    14. </xs:complexType>
    15. </xs:element>
    16. </xs:sequence>
    17. </xs:complexType>
    18. </xs:element>
    19. <xs:element name="NewDataSet" msdata:IsDataSet="true" msdata:UseCurrentLocale="true">
    20. <xs:complexType>
    21. <xs:choice minOccurs="0" maxOccurs="unbounded">
    22. <xs:element ref="Hauptebene" />
    23. </xs:choice>
    24. </xs:complexType>
    25. </xs:element>
    26. </xs:schema>


    Das Schema kann ich dann als DataSet.xsd ins Projekt importieren und aus der Toolbox ein typisiertes DataSet Element erstellen.

    Mache ich nichts weiteres, so wird die XML in <NewDataSet> eingeklammert.
    Neue Zeilen werden auch weiterhin falsch eingehängt.

    XML-Quellcode

    1. <NewDataSet>
    2. <Hauptebene>
    3. <Spalte1>Bonn</Spalte1>
    4. <Spalte2>Hamburg</Spalte2>
    5. <Tabelle1>
    6. <Spalte1>Elbe</Spalte1>
    7. <Spalte2>Weser</Spalte2>
    8. </Tabelle1>
    9. <Tabelle1>
    10. <Spalte1>Rhein</Spalte1>
    11. <Spalte2>Mosel</Spalte2>
    12. </Tabelle1>
    13. </Hauptebene>
    14. <Tabelle1>
    15. <Spalte1>Donau</Spalte1>
    16. <Spalte2>Iller</Spalte2>
    17. </Tabelle1>
    18. </NewDataSet>


    Wo liegt denn jetzt der Fehler?


    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „seelenreiter“ ()

    VaporiZed schrieb:

    hier geht's zu den vier Views, ein sehr gutes Tutorial vom EdR.


    seelenreiter schrieb:


    (...)Ich habe leider vom typisiert - untypisiert (noch) keinen blassen Schimmer. Kennst du, kennt jemand ein Tutorial dazu?

    Das von Kollege @VaporiZed vorgeschlagene Tutorial beschäftigt sich genau mit diesem Thema. Haste gar nicht angeschaut? :(

    Schau dor die Videos auf jeden Fall an, angefahren was man.da alles im Designer zusammen klickern kann ohne eine. Zeile Code zu schreiben.
    "Gib einem Mann einen Fisch und du ernährst ihn für einen Tag. Lehre einen Mann zu fischen und du ernährst ihn für sein Leben."

    Wie debugge ich richtig? => Debuggen, Fehler finden und beseitigen
    Wie man VisualStudio nutzt? => VisualStudio richtig nutzen
    ok, die Videos bringen mich nicht weiter.

    Ich versuche es noch einmal:

    Gegeben ist eine XML Datei. Das Format stammt nicht von mir und ich habe keine Einfluss auf das Layout.

    Vereinfacht (zum lernen für mich) schaut die XML so aus:

    XML-Quellcode

    1. <?xml version="1.0" encoding="UTF-8"?>
    2. <device>
    3. <sshPassword>admin</sshPassword>
    4. <sshUserId>admin</sshUserId>
    5. </device>


    Nehme ich ein untypisiertes Dataset und schaue mir die Tabelle "device" in einem Datagriedview an,

    VB.NET-Quellcode

    1. dsDeviceNT = New DataSet
    2. dsDeviceNT.ReadXml("..\..\device.xml")
    3. dgv1.DataSource = dsDeviceNT
    4. dgv1.DataMember = dsDeviceNT.Tables("device").TableName.ToString


    sehe ich 2 Spalten "sshPassword" und "sshUserId" mit einer Datarow mit den Werten "admin" und "admin"
    Soweit gut. Verändern und Speichern geht auch. Ist aber im Handling sehr mühsam.

    ---------------------------------------
    Jetzt füge ich dem Projekt ein "Dataset1.xsd" Objekt hinzu und erstelle eine Tabelle "device" mit 2 Colums "sshPassword" und "sshUserId".
    Anschließend füge ich der Form ein Dataset Objekt Typisiert "Dataset_XML_Problem.DataSet1" hinzu und lade die Datei.

    VB.NET-Quellcode

    1. dsDeviceT.ReadXml("..\..\device.xml")
    2. dgv2.DataSource = dsDeviceT
    3. dgv2.DataMember = dsDeviceT.Tables("device").TableName.ToString


    Schaue ich mir nun das DataGriedView an, sehe ich beide Colums aber keine Datarow. :(

    Ja, ich bin mir sicher, die XML passt nicht zur erstellten DataSet1.xsd. Kann ich die XSD irgendwie anpassen? Wie gesagt, die XML steht fest und einen Converter schreiben ist bescheiden...
    --------------------------------------
    Nächster Ansatz. Angenommen, ich muss eine XML neu erstellen.

    Ich nehme ein neues Dataset "nicht typisert" und erstelle eine Tabelle "device"

    VB.NET-Quellcode

    1. dsDeviceM = New DataSet
    2. Dim fnNewTable As New DataTable
    3. fnNewTable.TableName = "device"
    4. fnNewTable.Columns.Add("sshPassword", GetType(String)).DefaultValue = "admin"
    5. fnNewTable.Columns.Add("sshUserId", GetType(String)).DefaultValue = "admin"
    6. 'neue Row einfügen
    7. Dim fnNewRow As DataRow = fnNewTable.NewRow()
    8. fnNewTable.Rows.Add(fnNewRow)
    9. 'Tabelle zum Dataset hinzufügen
    10. dsDeviceM.Tables.Add(fnNewTable)


    Im DataGrieView schaut alles Top aus, ABER
    schreibe ich die XML Datei weg,

    VB.NET-Quellcode

    1. dsDeviceM.WriteXml("..\..\out.xml")


    Wird die XML in <newDataSet> eingefasst. Womit halt die XML für den eigentlichen Zweck unbrauchbar wird.

    XML-Quellcode

    1. <?xml version="1.0" encoding="utf-8"?>
    2. <newDataset>
    3. <device>
    4. <sshPassword>admin</sshPassword>
    5. <sshUserId>admin</sshUserId>
    6. </device>
    7. </newDataSet>


    Letzte Frage: Gibt es eine Möglichkeit diese <newDataSet> zu verhindern?
    nicht dassich wüsste.
    Die dir vorgegebene Xml-Datei ist eben keine Dataset-Datei - dassis eben eiglich inkompatibel.
    In diesem Fall könnte ich mir aber als "Nachbearbeitungs-Hack" einen Converter vorstellen, der den <newDataset>-Tag zwischenschiebt, wenns als Dataset geladen werden soll, und denselben entfernt, wenn Kompatiblität mit dem Original-Datenformat gefordert ist.
    Das ginge auch ohne Dateizugriff - mit einem StringWriter kann Dataset auch in einen String schreiben anstatt in eine Datei.
    Das ist mir klar. Danke für den Ansatz.

    Mir ging es einfach ums Begreifen / lernen.

    Mittlerweile habe ich mich schon ein wenig durch das Thema gebissen.
    Ich kann im untypisierten Dataset auch die anfänglich mit eingefügten Untertabellen erstellen und einhängen.
    Ist aber halt echt mühsam.

    Trotzdem Mercie !!!
    Ich seh grad das Problem nicht. Nennt mich naiv, aber ich hätte jetzt einfach mir den XML-Text für das DataSet (tDS (= typisiertes DataSet)) aus der Datei zusammengebastelt und an das DataSet (per ReadXML) verfüttert, welches ich im DataSet-Designer erstellt und dann auf das Form gezogen hab.
    Fütterdaten bestehen aus:
    <DeinTds.DataSetName xmlns="DeinDataSet.Namespace">
    die Daten aus der Datei ab Zeile 2
    </DeinTds.DataSetName>

    Ok, Konjunktiv beiseite. Hab ich gemacht und läuft. Jetzt die Frage: Warum sollte man sowas besser nicht machen?
    Das ermöglicht mir nun, ohne Code-Rumpfriemelei und ohne viele Codezeilen endlich zu arbeiten.
    Bilder
    • feed XML-RawData.png

      11,06 kB, 826×486, 206 mal angesehen
    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.
    ID-Spalte ausblenden: entsprechend den Tut-Videos vom EdR (auch wenn man dazu kein Tut braucht): Klick auf den SmartTag des DGV ( [>] oben rechts am DGV-Rahmen), Spalten bearbeiten, Spalte ID anwählen, [Entfernen]
    "Wenn die ID nicht in der ersten Zeile steht" - wo? In der DataTable "device"? Dann läuft es trotzdem. Oder meinst Du "sshUserId"? Da bitte genau sein, sonst weiß ich nicht, worum es geht. Kann ich aber auch nicht bestätigen. Habe folgende Testdaten in der Rohdatei:
    <device>
    <sshPassword>admin</sshPassword>
    <sshUserId>admin</sshUserId>
    </device>
    <device>
    <sshUserId>admin1</sshUserId>
    <sshPassword>admin2</sshPassword>
    </device>
    Und siehe da:
    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.
    Ich will ja keine Panik schieben, aber: An welcher Stelle glaubst Du, dass Du irgendwelche manuellen Zuweisungen machen müsstest? Ich habe nichts außer das oben gezeigte tDS, das automatisch gebundene DGV und die automatisch erzeugten BindingSources. Ich habe als eigenen, selbstgeschriebenen Code außerdem nur die Erzeugung des XML-Codes für's tDS. Sonst gar nix. Der Rest läuft automatisch im Hintegrund ab. Was willst Du da noch manuell zuordnen?
    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.
    Heureka

    XML ist ein Ar***loch. Und ich bin schuld. :P

    Wenn man sich halt an einem Problem entlang hangelt und sich das Thema selbst erschließt, läuft man halt gegen Wände, die man mit einer grundlegenden Schulung erklärt bekäme.

    Zur Erklärung:
    Die XML wird normal von einem teuren Server erstellt und muss dann auch nicht verändert werden.
    Um den teuren Server zu umgehen, kursieren massig Anleitungen im Web. Die dort beschriebenen XML Dateien sind für Menschen auch weitestgehend gleich.
    Wir sind ja auch flexibel und erkennen, wenn die Reihenfolge nicht stimmt. Beim nicht typisierten Dataset fällt der Unterschied nicht auf, da man die Attribute einzeln anspricht.

    XML-Quellcode

    1. <device>
    2. <sshPassword>adminpw</sshPassword>
    3. <sshUserId>admin</sshUserId>
    4. </device>


    ist genau so gut wie

    XML-Quellcode

    1. <device>
    2. <sshUserId>admin</sshUserId>
    3. <sshPassword>adminpw</sshPassword>
    4. </device>


    Für typisierte XML Datasets sind sie aber unterschiedlich.Im zweiten Fall wird das Dataset nicht einlesen. Die Felder bleiben leer.
    Wenn man dann beim Testen mit verschiedenen XML Dateien jongliert, kommt es ggf. zum Blinkerfehler. Geht, geht nicht, geht, geht nicht.

    Das erste Fallstrick war aber bereits vorher, dass man zwar die XML einlesen und bearbeiten konnte. In der gespeicherten XML Datei dann aber auf einmal ein neuer Root Node "NewDataSet" auftauchte. Natürlich bin ich von einem Fehler bei mir ausgegangen und habe mich (erfolgreich) dumm und dusselig gesucht.
    Das Problem lässt sich relativ einfach mit einem Umweg über einen String lösen.

    Aufgrund der unterschiedlichen XML Schemas im Web, bleibt mir nichts anderes übrig, als das "vorgefundene" einzulesen und dann typisiert abzuspeichern.
    Das Jahr ist ja noch jung.

    An dieser Stelle noch einmal vielen lieben Dank an alle, die mir versucht haben zu helfen. Es sind die richtigen Schlussfolgerungen dabei herausgekommen.
    Wie gesagt - post#9
    Konvertiere die Xml in eine gültige typisierte Dataset-Datei und zurück.
    So macht man das halt bei Kompatiblitäts-Problemen.
    Für's gezeigte Xml braucht man dafür keine 20 Zeilen Code, einfach mit String.Split und String.Concat.

    Wurstel dich nicht dumm und dämlich mit untypisierten Datasetsen.

    Mit untypisierten Datasetsen umzugehen ist ein grauenhafter Programmierstil, und was du dir da angewöhnst macht dich zum Grotten-Coder, weil du so nie lernen wirst, Databinding anzuwenden, und typisiert zu programmieren.

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „ErfinderDesRades“ ()

    Dass die Attributreihenfolge in der XML eine Rolle spielen soll, kann ich erstmal nicht bestätigen.

    XML-Quellcode

    1. <?xml version="1.0" standalone="yes"?>
    2. <TdsSSH xmlns="http://tempuri.org/TdsSSH.xsd">
    3. <device>
    4. <sshPassword>a</sshPassword>
    5. <sshUserId>b</sshUserId>
    6. <bla>c</bla>
    7. </device>
    8. <device>
    9. <bla>f</bla>
    10. <sshUserId>e</sshUserId>
    11. <sshPassword>d</sshPassword>
    12. </device>
    13. </TdsSSH>

    Diese Daten frisst mein tDS ohne Probleme. Trotz unterschiedlicher Reihenfolge. Oder hab ich da was falsch verstanden? Na wurscht, Du bist weitergekommen, das war ja das Ziel.
    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

    erst einmal vielen Dank für deine Zeit und Hilfe.

    Ich bin mittlerweile den Weg des Converters gegangen.
    Sprich, ich lese die XML Datei in ein Dataset und konvertiere die Daten dann in ein typisiertes Dataset.
    Da der Ursprung der XML unterschiedlichen Quellen und dann der humanden Anpassung unterliegt, kann es wirklich zu sehr vielen unterschiedlichen Stilblüten kommen. Freistil halt.

    Als ich letztens ausprobiert hatte die Attributfolge zu ändern, hat mir Visual Studio den Finger gezeigt.

    Ganz ehrlich? Ich habe in den letzten Wochen so viele Test Projekte erstellt, dass ich da nicht mehr durchblicke.
    Zumal mich jetzt der Job auch wieder eingefangen hat.
    Ich habe viel über XML und Dataset gelernt. Von daher hat es sich für mich gelohnt. :)

    Liebe Grüße
    Ingo