XML Datei mit xDocument erstellen

  • VB.NET

Es gibt 7 Antworten in diesem Thema. Der letzte Beitrag () ist von Yanbel.

    XML Datei mit xDocument erstellen

    Hallo zusammen,

    leider gibt es schon wieder ein Problem. Obwohl ich schon 3 unterschiedliche Ansätze versucht habe eine XML zu erstellen, lässt sich mit keiner Methode das gewünschte Ergebnis erzielen. Aktuell versuche ich es über ein xDocument. Das ist einfach und lässt sich soweit korrekt erstellen. Aber wie ändert man dann die Werte?

    VB.NET-Quellcode

    1. Dim xmlstring As XDocument = <?xml version='1.0' encoding='utf-16'?>
    2. <Task version="1.2" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task">
    3. <Triggers>
    4. <TimeTrigger>
    5. <StartBoundary>2019-05-30T14:44:44</StartBoundary>
    6. <Enabled>true</Enabled>
    7. </TimeTrigger>
    8. </Triggers>
    9. <Principals>
    10. <Principal id="Author">
    11. <LogonType>InteractiveToken</LogonType>
    12. <RunLevel>LeastPrivilege</RunLevel>
    13. </Principal>
    14. </Principals>
    15. <Settings>
    16. <DisallowStartIfOnBatteries>false</DisallowStartIfOnBatteries>
    17. <AllowStartOnDemand>true</AllowStartOnDemand>
    18. <Enabled>true</Enabled>
    19. <WakeToRun></WakeToRun>
    20. <Priority>7</Priority>
    21. </Settings>
    22. <Actions Context="Author">
    23. <Exec>
    24. <Command></Command>
    25. <Arguments></Arguments>
    26. </Exec>
    27. </Actions>
    28. </Task>
    29. Console.WriteLine("jetzt: " & xmlstring.<Task>.<Triggers>.<TimeTriggers>.@StartBoundary)
    30. Console.WriteLine("jetzt: " & xmlstring.<Triggers>.<TimeTriggers>.@StartBoundary)
    31. Console.WriteLine("jetzt: " & xmlstring.<Task>.<Triggers>.<TimeTriggers>.<StartBoundary>.Value)
    32. Console.WriteLine("jetzt: " & xmlstring.<Triggers>.<TimeTriggers>.<StartBoundary>.Value)
    33. xmlstring.<Task>.<Triggers>.<TimeTriggers>.@StartBoundary = "2019-05-30T14:00:00"
    34. xmlstring.Save("xDoc_schreiben_Utf16.xml")


    Die beiden Methoden auf die Werte zuzugreifen stammen aus dem Internet aus Beispielen. Leider funktioniert keine davon (man soll auf gleichem Weg dann auch schreiben können). Weil ich nihct ganz sicher war, ob das Wurzelelement "Task" mit aufgeführt sein muss, wurde es mit und ohne versucht. Was mache ich da falsch?

    Als weitere Möglichkeit sollte die XML einfach als Text gespeichert werden. Der Taskplaner beschwert sich dann aber über falsche Codierung. Ich weiss nicht wie man einen Text als UTF16 codiert speichert.

    3. Variante war das Erstellen der einzelnen Knotenpunkte und hinzufügen als Child usw. Dabei fügt mir VB aber überall den Namespace xmlns="" hinzu. Das mag der Taskplaner auch wieder nicht.

    Kann mir da einer weiterhelfen?

    GRuß

    eddi
    Scheinbar funktioniert folgendes:

    Spoiler anzeigen

    VB.NET-Quellcode

    1. Dim XML_Text As New Xml.XmlDocument
    2. XML_Text.LoadXml("<?xml version='1.0' encoding='utf-16'?>" &
    3. "<Task version=""1.2"" xmlns=""http://schemas.microsoft.com/windows/2004/02/mit/task"">" &
    4. "<Triggers>" &
    5. "<TimeTrigger>" &
    6. "<StartBoundary>" & Startzeit_string & "</StartBoundary>" &
    7. "<Enabled>true</Enabled>" &
    8. "</TimeTrigger>" &
    9. "</Triggers>" &
    10. "<Principals>" &
    11. "<Principal id=""Author"">" &
    12. "<LogonType>InteractiveToken</LogonType>" &
    13. "<RunLevel>LeastPrivilege</RunLevel>" &
    14. "</Principal>" &
    15. "</Principals>" &
    16. "<Settings>" &
    17. "<DisallowStartIfOnBatteries>false</DisallowStartIfOnBatteries>" &
    18. "<AllowStartOnDemand>true</AllowStartOnDemand>" &
    19. "<Enabled>true</Enabled>" &
    20. "<WakeToRun>" & CStr(PC_wecken).ToLower & "</WakeToRun>" &
    21. "<Priority>7</Priority>" &
    22. "</Settings>" &
    23. "<Actions Context=""Author"">" &
    24. "<Exec>" &
    25. "<Command>" & Programm & "</Command>" &
    26. "<Arguments>" & Argumente & "</Arguments>" &
    27. "</Exec>" &
    28. "</Actions>" &
    29. "</Task>")
    30. XML_Text.Save(eigener_Pfad & "Task XML\" & Dateiname & "_01" & ".xml")


    Das wäre dann Variante 4. :) Im Grunde ja nun ganz einfach, aber es hat Tage gedauert, bis ich das Passende endlich gefunden hab. (natürlich wieder kurz NACHDEM ein Beitrag erstellt wurde... :rolleyes: )
    Vielleicht hilft's ja mal einem...

    Gruß

    eddi
    Welchen Sinn soll es denn haben, das XmlDocument von Hand im Programm zu erstellen und als Datei auszugeben? Da kann ich es doch gleich mit Notepad++ schreiben.

    Du musst einmal entscheiden ob du mit XmlDocument oder XDocument arbeitest, das erste ist sehr viel älter und man muss mehr Code schreiben, das zweite ist neuer, arbeitet mit Linq etc.
    Google da mal nach. Dann musst Du die Elemente (Node, Element und Attribute) erst mal definieren und ihnen einen Wert zuweisen. Damit baust du dann quasi die Tabellenstruktur auf. Dann fügst du den Knoten dem Document zu (Append).

    Du kannst auch einen ganz anderen Weg gehen: Im Designer ein (streng) typisiertes Dataset mit den Tabellen und Feldern anlegen und mit einem einfachen thisDataSet.WriteXml(filename) schreibst du dann die XML.
    Ehrlich gesagt ist mir die Methode völlig egal! Sie muss nur funktionieren. Gegooglet wurde in den letzen Tagen soviel, dass ich schon Angst hatte da gesperrt zu werden. :)
    Wie unter Punkt 3 im ersten Beitrag schon erwähnt hab ich mich schon damit beschäftigt die Nodes, Elemente usw. zu erstellen und als Child einzufügen. Im Prinzip funktionierte das auch. Die oben gezeigte XML-Datei ließ sich damit aber nicht erstellen. In den Childs erstellte das Programm dann einfach einen Namespace xmlns="", was dann zu Fehlern führte.
    Bei einem xDocument kann ich keine dynamischen Werte aus einer Variablen einfügen. (also das geht vielleicht irgendwie, aber ich kann's nicht, daher ja mein Beitrag)
    Außerdem hat sich das Thema wie gesagt erledigt, denn inzwischen lässt sich ja eine passende XML erstellen. Und wie man sieht werden da Werte aus Variablen eingefügt. Und dann schreibt schtasks.exe den Task aus dieser XML in den Taskplaner.

    Gruß

    eddi
    Moin,
    wenn die Xml Datei genau so strukturiert sein muß, wird er bei ChildNodes Probleme bekommen, wenn diese aus einem DataSet gefüllt werden sollen.

    XML-Quellcode

    1. <Actions Context="Author">
    2. <Exec>
    3. <Command></Command>
    4. <Arguments></Arguments>
    5. </Exec>
    6. </Actions>


    DataSet.WriteXml erstellt, meines Wissens nach, nur das XmlElement(in dem Fall Actions = DataTable) und könnte die Eigenschaften (Rows(x).Command, Arguments) als DataColumn erstellen. Mit Exec wird es da schwierig.

    Ich erstelle mir Xmls lieber als komplette Klasse mit Unterklassen und lasse diese über System.Xml.Serialization.XmlSerializer(GetType(DeineKlasse)) serialisieren. Dies funktioniert prächtig sowohl lesend als auch schreibend.
    Die Daten würde man dann im weiteren Schritt an die von dir erstellte Klasse schicken. Wenn du Interesse hast, kann ich dir gerne mal ein Beispiel fertigmachen.
    @BlueLagoonX: Das ist sehr nett. Aber ich fürchte das ist auch sehr viel Arbeit. Der Aufbau muss EXAKT so sein, wie in meinem 2. Beitrag gezeigt, sonst nimmt der Taskplaner die XML nicht an. Probleme wird's da vermutlich mit den Attributen innerhalb der Elemente geben. Besonders hier:

    XML-Quellcode

    1. <Task version="1.2" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task">

    Das Projekt nutzt sogar schon die Serialisierung, um eine Collection aus einer Klasse als XML zu speichern. Ich hab aber keine Ahnung, wie man dort eine solche Struktur nachbilden könnte.
    In älteren Projekten nutz ich häufig DataTable.writexml("dings.xml"). (oder so ähnlich ist der Befehl)
    Einseits würde mich die modernere Methode über die Klasse schon interessieren, aber investiere bitte nicht viel Zeit in das Beispiel. Wie Codiert der Serializer eigentlich? Die XML muss in UTF16 sein, UTF8 gefällt dem feinen Herrn Taskplaner auch wieder nicht! :)

    Gruß

    eddi
    Der vorgesehene Weg ist, dass es für diese Task.xml eine Schema-Datei gibt (.xsd).
    Aus der Schema-Datei kann man sich den Klassen-Code generieren lassen, und dann hat man Task-Objekte, wo man die Properties ganz nach Bedarf setzen kann.
    und zum Speichern serialisieren.
    Zu diesem Konzept gehört halt auch, dass der hersteller des Objektes irgendwo die .xsd veröffentlicht/dokumentiert hat.

    Notfalls kann man auch mittm Visualstudio aus einer Xml eine .xsd ableiten lassen - aber deren Datentyp-Angaben sind dann alles String, weil das ist der kleinste gemeinsame Nenner der Darstellung von Daten in Xml.

    ErfinderDesRades schrieb:

    Der vorgesehene Weg ist, dass es für diese Task.xml eine Schema-Datei gibt (.xsd).
    Aus der Schema-Datei kann man sich den Klassen-Code generieren lassen, und dann hat man Task-Objekte, wo man die Properties ganz nach Bedarf setzen kann.
    und zum Speichern serialisieren.


    Hierzu habe ich ein Tutorial geschrieben. Statt der automatisierten Erstellung der Klassen aus dem xsd-Schema ist dort beschrieben, wie du die Klassen selber anlegst.

    Hier der Link


    Ein Computer wird das tun, was du programmierst - nicht das, was du willst.