Laden...

Object XmlSerializer, Attribute fügt sich im Root-Element ein

Erstellt von jok3r89 vor 6 Jahren Letzter Beitrag vor 6 Jahren 1.825 Views
J
jok3r89 Themenstarter:in
70 Beiträge seit 2017
vor 6 Jahren
Object XmlSerializer, Attribute fügt sich im Root-Element ein

Hallo ich will aus einem Object ein XML erstellen der Eintrag soll dann noch eine Attribute bekommen. Leider wird das Attribute nicht erkannt.
Die Klasse ->


   // Config
    [Serializable()]
    public class S7Model
    {
        [XmlAttribute]
        public String S7Name = "dummy";

        public Destination destination = new Destination();
        public class Destination
        {
            public String ip { get; set; }
            public int rack { get; set; }
            public int slot { get; set; }
        }

        public Settings settings = new Settings();
        public class Settings
        {   // data info
            public Sharp7.S7Consts.S7Tag dbAccess;
        }
    }

Die Methode ->


      public void addS7Com(S7Model model)
        {
            #region Save the object
        
            // Create a new XmlSerializer instance with the type of the test class
            XmlSerializer SerializerObj = new XmlSerializer(typeof(S7Model));

            // Create a new file stream to write the serialized object to a file
            string path = Path.Combine(Environment.CurrentDirectory, @"Data\", "S7Model.xml");

            if (!System.IO.File.Exists(path))
            {
                System.IO.Directory.CreateDirectory(@"Data\");
            }
            TextWriter WriteFileStream = new StreamWriter(path);
            //Path.Combine(Environment.CurrentDirectory, @"Data\", "S7Model.xml"));

            SerializerObj.Serialize(WriteFileStream, model);

            // Cleanup
            WriteFileStream.Close();

            #endregion
        }

Das Ergebnis ist ->


<?xml version="1.0" encoding="utf-8"?>
<S7Model xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" S7Name="dummy">
  <destination>
    <ip>000.000.000.110</ip>
    <rack>1</rack>
    <slot>1</slot>
  </destination>
  <settings>
    <dbAccess>
      <Area>0</Area>
      <DBNumber>0</DBNumber>
      <Start>0</Start>
      <Elements>0</Elements>
      <WordLen>0</WordLen>
    </dbAccess>
  </settings>
</S7Model>

Woran kann das liegen ? Mir fehlt eben als Attribute der String "S7Name"
Gruß

2.078 Beiträge seit 2012
vor 6 Jahren

Es ist doch da?

Schau mal am Ende der Zeile mit den Namespaces.

J
jok3r89 Themenstarter:in
70 Beiträge seit 2017
vor 6 Jahren

Ohje, es war ja ein langer Tag... Danke
Wie bekomme ich denn


 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" S

das hier weg ?
Für mich ist das unnütz, vor allem steht meine ID genau dort in dieser Zeile.
Die XML soll bei mir Verbindungen darstellen, kann man das so lassen?
Für jede Verbindung habe ich mir vorgestellt vergebe ich eine ID.
Jetzt frag ich mich aber ist das so praktikabel, vor allem weil die Liste auch immer wieder um eine Verbindung über die GUI erweitert werden kann.

Gruß

J
jok3r89 Themenstarter:in
70 Beiträge seit 2017
vor 6 Jahren

Diese Form stelle ich mir vor ->

<?xml version="1.0" encoding="utf-8"?>
<S7Model xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <id id = 0>
  	<name>dummy</name>
  	<destination>
    	<ip>000.000.100.000</ip>
    	<rack>1</rack>
    	<slot>1</slot>
  	</destination>
  	<settings>
    	<dbAccess>
      	<Area>0</Area>
      	<DBNumber>0</DBNumber>
      	<Start>0</Start>
      	<Elements>0</Elements>
      	<WordLen>0</WordLen>
    	</dbAccess>
  	</settings>
  </id>
  <id id = 1>
  	<name>dummy</name>
  	<destination>
    	<ip>000.000.100.000</ip>
    	<rack>1</rack>
    	<slot>1</slot>
  	</destination>
  	<settings>
    	<dbAccess>
      	<Area>0</Area>
      	<DBNumber>0</DBNumber>
      	<Start>0</Start>
      	<Elements>0</Elements>
      	<WordLen>0</WordLen>
    	</dbAccess>
  	</settings>
  </id>
</S7Model>
J
jok3r89 Themenstarter:in
70 Beiträge seit 2017
vor 6 Jahren

Okay also ich glaub ich hab es richtig gemacht zu mindestens sieht es so danach aus

<S7Models xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <s7 ID="1">
    <Destination>
      <ip>001.000.000.000</ip>
      <rack>1</rack>
      <slot>1</slot>
    </Destination>
    <Settings>
      <dbAccess>
        <Area>0</Area>
        <DBNumber>0</DBNumber>
        <Start>0</Start>
        <Elements>0</Elements>
        <WordLen>0</WordLen>
      </dbAccess>
    </Settings>
  </s7>
</S7Models>

Das Klassenmodel sieht so aus ->

  // Config
    [XmlRoot("S7Models"),Serializable()]
    public class S7Model
    {   //database id 
        [XmlElement("s7")]
        public S7 s7 = new S7();
    }
    public class S7
    {
        [XmlAttribute("id")]
        public string id = "0";
        [XmlElement("Destination")]
        public Destination destination = new Destination();
        public class Destination
        {
            public String ip { get; set; }
            public int rack { get; set; }
            public int slot { get; set; }
        }
        [XmlElement("Settings")]
        public Settings settings = new Settings();
        public class Settings
        {   // data info
            public Sharp7.S7Consts.S7Tag dbAccess;
        }

    }

Sieht das eher gebastelt aus oder auch so benutzbar ?
Ich habe XML s noch nie erstellt daher weiß ich noch nicht so genau worauf es ankommt.
Wenn ich das XML jetzt erweitern will, um einen zweiten Eintrag, wie würde man da am besten vorgehen ? Oder gibts dazu eine Klasse die sowas handhabt ?

2.078 Beiträge seit 2012
vor 6 Jahren

Wie die XML-Struktur aufgebaut ist, bleibt ja dir überlassen.
Der XmlSerializer baut das anhand deiner Klassen-Stuktur auf.
Wenn Du da also zwischendrin noch eine id-Klasse haben willst, dann bau eben eine id-Klasse mit id-Property, die dann die eigentlichen Daten enthält.

Allerdings finde ich die Namen nicht sehr gelungen.
Ich würde das (zum Beispiel) so benennen:

<?xml version="1.0" encoding="utf-8"?>
<S7Models>
  <S7Model id="0">
      <name>dummy</name>
  </S7Model>
  <S7Model id="1">
      <name>dummy</name>
  </S7Model>
</S7Models>

Außerdem solltest Du bei allem, was IDisposable implementiert, die using-Anweisung verwenden, vorausgesetzt, es ist möglich.
Das kümmert sich darum, dass der Aufruf von Dispose sicher gestellt ist.
Dein StreamWriter wäre so ein Fall, der hält intern einen Stream (der FileStream), der geschlossen werden muss.
In diesem konkreten Fall dürfte das kein soo großes Problem sein, weil der Destruktor implementiert ist und der Garbage Collection den Stream irgendwann automatisch auf räumt, aber es gibt mit Sicherheit auch eine Situation oder andere Klassen, wo das problematisch wird.

Wenn ich deinen Code entsprechend anpasse:

public void addS7Com(S7Model model)
{
    #region Save the object

    // Create a new XmlSerializer instance with the type of the test class
    XmlSerializer SerializerObj = new XmlSerializer(typeof(S7Model));

    // Create a new file stream to write the serialized object to a file
    string path = Path.Combine(Environment.CurrentDirectory, @"Data\", "S7Model.xml");

    if (!System.IO.File.Exists(path))
    {
        System.IO.Directory.CreateDirectory(@"Data\");
    }

    using (TextWriter WriteFileStream = new StreamWriter(path))
    {
        //Path.Combine(Environment.CurrentDirectory, @"Data\", "S7Model.xml"));

        SerializerObj.Serialize(WriteFileStream, model);
    }

    #endregion
}

Und wie Du die Namespaces weg bekommst:
http://bfy.tw/EqdO 😛
Da findest Du How to serialize an object to XML without getting xmlns=“…”?

PS:
Gut, der erste meiner Antwort fällt dann wohl weg ^^

J
jok3r89 Themenstarter:in
70 Beiträge seit 2017
vor 6 Jahren

Okay danke zum Thema XML, wie geht man das an? Ich hab zwei alternativen erstere ich lade die alte XML und erzeuge daraus wieder ein Objekt und verlängere die liste mit der ID. Oder es gibt eine Möglichkeit wo ich genau auf das Attribut zugreifen kann, bzw danach nochmal eines anhängen kann?

2.078 Beiträge seit 2012
vor 6 Jahren

Okay danke zum Thema XML, wie geht man das an? Ich hab zwei alternativen erstere ich lade die alte XML und erzeuge daraus wieder ein Objekt und verlängere die liste mit der ID. Oder es gibt eine Möglichkeit wo ich genau auf das Attribut zugreifen kann, bzw danach nochmal eines anhängen kann?

Wie meinst Du das?
Meinst Du das Verändern von deinem Format?
Also das, was Du da geschrieben hast:

Sieht das eher gebastelt aus oder auch so benutzbar ?
Ich habe XML s noch nie erstellt daher weiß ich noch nicht so genau worauf es ankommt.
Wenn ich das XML jetzt erweitern will, um einen zweiten Eintrag, wie würde man da am besten vorgehen ? Oder gibts dazu eine Klasse die sowas handhabt ?

Also ich persönlich würde die Benamsung der Klassen beanstanden.
Keine Fields, sondern Properties und die sollten auch mit einem Großbuchstaben beginnen.
Außerdem würde ich von Nested Classes absehen.

Was das XML angeht, sehe ich da aber kein Problem.
Solange alles valide ist - und das ist es, das tut der XmlSerializer für dich - sollte alles andere auch klappen.

Problematisch sind dagegen neue Inhalte oder wenn alte Inhalte weg fallen.
Auf C#-Code-Seite kannst Du da nicht mehr viel tun, als die Properties hinzuzufügen oder zu entfernen.
Wie sich der XmlSerializer da verhält, weiß ich nicht, ich würde aber darauf tippen, dass der das ignoriert. Er serialisiert bzw. deserialisiert alles, was in der Klasse ist. Gibts im XML zu viele Inhalte, ignoriert er die. Gibts eine Property, dessen Gegenstück im XML nicht existiert, ignoriert er die auch.

In der Nutzung beim Einlesen bzw. nachdem Du das Model-Objekt auswertest, musst Du dich dann darum kümmern, dass Du passende Default-Werte verwendest oder entsprechende Fehler wirst, wenn dir Daten fehlen.
Ich würde aber auch sagen: Darum kümmerst Du dich, sobald es soweit ist 😉 Du solltest vorher nur darauf achten, das ganze XML Serialisieren/Deserialisieren klug zu abstrahieren, dass Du später nur eine Stelle anpassen musst und nicht tausend.

Wenn das XML-Format komplex wird und sich auch mal stark ändern kann, dann solltest Du einen Blick auf LINQ to XML werfen.
Das serialisiert/deserialisiert zwar nicht mehr so schön automatisch, dafür hast Du aber auch sehr viel mehr Möglichkeiten, beim Serialisieren bzw. Deserialisieren einzugreifen.

J
jok3r89 Themenstarter:in
70 Beiträge seit 2017
vor 6 Jahren

Ich erzeuge mein XML File wenn ich eine Verbindung hinzufüge und noch kein File vorhanden ist mit dem ersten Eintrag.
Dann soll ein zweiter Eintrag hinzugefügt werden. Dann frage ich mich wie gehe ich das an.

Variante 1 Ich kann das XML anpassen und den neuen Eintrag hinzufügen

Variante 2 Ich halte das Object am leben und füge mit add in einer liste was hinzu.
Wenn das Object entfernt wird erzeuge ich noch das XML aus dem Object.
Anderes rum lade ich das XML wenn ich auf das Object zugreifen will
Ich hoffe man versteh jetzt was ich meine. Mir geht es darum wie man mit sowas arbeitet.

Gruß

2.078 Beiträge seit 2012
vor 6 Jahren

Ach darauf wolltest Du hinaus 😄

Beim XmlSerializer kommst Du nicht drum herum, die ganze Datei immer komplett neu zu schreiben.
Also hast Du zwei Möglichkeiten:1.Du behältst die Liste aller Einträge irgendwo am leben, schreibst dort rein und schreibst jedes Mal die XML-Datei 1.Du liest jedes Mal die Datei ein, fügst dem frisch deserialisieren Listen-Objekt ein neues Element hinzu und speicherst das dann wieder

Bevor Du nach Performance fragst: Das kannst Du vernachlässigen, man kann es vielleicht messen, aber spürbar wird es vermutlich nicht sein.

D
985 Beiträge seit 2014
vor 6 Jahren

Ich habe XML s noch nie erstellt daher weiß ich noch nicht so genau worauf es ankommt.

Darauf, dass man einen XML-Serializer verwendet (so wie du das machst) und nicht versucht die Datei von Hand zu bauen.

😁

16.806 Beiträge seit 2008
vor 6 Jahren

Man kümmert sich so lange nicht selbst um das Schreiben einer XML sondern nimmt einen Serializer, bis man es wirklich selbst tun muss.
Und das ist dann in 99% der Fälle der Fall, wenn die XML mal mehrere GB an Daten hat, dann knallt der Standard Serializer nämlich.

Vorher versucht man so viel wie möglich zu automatisieren.

J
jok3r89 Themenstarter:in
70 Beiträge seit 2017
vor 6 Jahren

Ich hab das nach meinem Kommentar auch so umgesetzt und es funktioniert bisher. Sogar echt sehr zügig also völlig ausreichend. Mit der Lösung erübrigen sich dann auch gleich noch viele andere Probleme. Ein Objekt kann ich eben besser manipulieren als eine dumme text Datei 😃.
Schon mal vielen Dank.