Laden...

Namespaces beim XmlSerializer richtig/schöner zuordnen

Erstellt von IchRoque81 vor 13 Jahren Letzter Beitrag vor 13 Jahren 2.414 Views
IchRoque81 Themenstarter:in
36 Beiträge seit 2008
vor 13 Jahren
Namespaces beim XmlSerializer richtig/schöner zuordnen

verwendetes Datenbanksystem: keins

Hallo liebe Community!

Ich habe ein Problem mit dem Serialisieren von Objekten. Weder mein schlauer Wälzer, C#4.0 in a nutshell, noch zahlreiche Tutorials aus dem Internet konnten mir eine Lösung bieten. Daher hoffe ich, dass mir einer von euch weiterhelfen kann, wenn es überhaupt eine Lösung dafür gibt 😁

Folgender, vereinfachter, Aufbau ist gegeben:
Eine Station beinhaltet einen Controller, sowie eine Liste von Devices. Der Controller, als auch die Devices, besitzen wiederrum eine Liste von Modulen (siehe folgenden Code).


    public abstract class Base
    {
        public string Name { get; set; }
        public byte? Address1 { get; set; }
        public string IpAddress { get; set; }
    }

    [XmlRoot(Namespace = "http://Modul")]
    public class Modul : Base
    {
        public string IpAddress2 { get; set; }
    }

    [XmlRoot(Namespace = "http://Controller")]
    public class Controller : Base
    {
        public string ConName { get; set; }
        private List<Modul> _modules;
        public List<Modul> Modules
        {
            get
            {
                if (_modules == null)
                    _modules = new List<Modul>();
                return _modules;
            }
            set
            {
                _modules = value;
            }
        }  
    }
    [XmlRoot(Namespace = "http://Device")]
    public class Device : Base
    {
        private List<Modul> _modules;
        public List<Modul> Modules
        {
            get
            {
                if (_modules == null)
                    _modules = new List<Modul>();
                return _modules;
            }
            set
            {
                _modules = value;
            }
        }
    }
    [XmlRoot(Namespace = "http://Station")]
    public class Station
    {
        public Controller Controller = new Controller();
        private List<Device> _devices;
        public List<Device> Devices
        {
            get
            {
                if (_devices == null)
                    _devices = new List<Device>();
                return _devices;
            }
            set
            {
                _devices = value;
            }
        }
    }

Ziel ist es, dass mit XmlSerializer zu serialisieren und wieder deserialisieren zu können. Damit dem Benutzer das Editieren der XML erleichtert wird, verwende ich ein entsprechendes XML-Schema.
Das Ergebnis der Serialisierung sieht folgendermaßen aus:


  <?xml version="1.0" ?> 
  - <Station xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://Station">
    - <Controller>
      <Name xmlns="http://Controller">ConName</Name> 
      <Address1 xsi:nil="true" xmlns="http://Controller" /> 
      <IpAddress xmlns="http://Controller">192.168.1.1</IpAddress> 
    - <Modules xmlns="http://Controller">
      - <Modul>
          <Name xmlns="http://Modul">conMod1</Name> 
          <Address1 xsi:nil="true" xmlns="http://Modul" /> 
          <IpAddress2 xmlns="http://Modul">192.168.1.2</IpAddress2> 
        </Modul>
      - <Modul>
          <Name xmlns="http://Modul">conMod2</Name> 
          <Address1 xsi:nil="true" xmlns="http://Modul" /> 
          <IpAddress2 xmlns="http://Modul">192.168.1.3</IpAddress2> 
        </Modul>
      </Modules>
    </Controller>
  - <Devices>
    - <Device>
      <Name xmlns="http://Device">Dev1</Name> 
      <Address1 xmlns="http://Device">0</Address1> 
    - <Modules xmlns="http://Device">
      - <Modul>
          <Name xmlns="http://Modul">dev1Mod1</Name> 
          <Address1 xsi:nil="true" xmlns="http://Modul" /> 
        </Modul>
      </Modules>
    </Device>
  </Devices>
  </Station>

Die Namespaces für Station, Controller, Device, usw. sind deshalb notwendig, weil der Anwender nicht nur eine gesamte Station serialisieren, sondern auch nur Teile diese Serialisieren können soll, und mit Hilfe des entsprechenden XML-Schemas leicht editieren.

Was mir an der Lösung jetzt nicht gefällt, und somit auch mein Problem ist, dass der Namespace auf Ebene jeden Tags steht. Ich würde mir wünschen, dass der Namespace vom Controller beispielsweise im Tag vom Controller steht, also so:


<Controller xmlns="http://Controller">
  <Name>ConName</Name>
  ...
</Controller>

Ist das Möglich und wenn ja wie?

Grüße aus dem schönen Bayern 8)

~ rock on ~

4.939 Beiträge seit 2008
vor 13 Jahren

Hallo,

du könntest dir mal die XmlSerializerNamespaces-Klasse ansehen.
Wenn du dann die einzelnen Namespaces zusammen mit jeweils einem Prefix angibst, z.B.


XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
ns.Add("m", "http://Modul");
ns.Add("c", "http://Controller");
ns.Add("d", "http://Device");
ns.Add("s", "http://Station");

und diese Liste dann an den Serializer übergibst


xmlSerializer.Serialize(file, station, ns);

Dann müßte der Serializer (wenn ich die Doku richtig verstehe) dann nur die Prefixe verwenden, d.h. z.B.


<Controller>
      <c:Name>ConName</Name>
      <c:Address1 xsi:nil="true" />
      <c:IpAddress>192.168.1.1</IpAddress>

</Controller>

IchRoque81 Themenstarter:in
36 Beiträge seit 2008
vor 13 Jahren

Hi Th69 und danke für die schnelle Hilfe!

Das bringt mich meiner Lösung schön näher 😉
Jetzt hab ich nur noch das Problem mit der Base-Klasse von mir. Aktuell sieht es so aus:


  <?xml version="1.0" ?> 
- <s:Station xmlns:m="http://Modul" xmlns:c="http://Controller" xmlns:d="http://Device" xmlns:s="http://Station">
  - <s:Controller>
      <c:Name>ConName</c:Name> 
      <c:Address1 d3p1:nil="true" xmlns:d3p1="http://www.w3.org/2001/XMLSchema-instance" /> 
      <c:IpAddress>192.168.1.1</c:IpAddress> 
    </s:Controller>
  </s:Station>

Wenn ich bei der Base-Klasse ebenfalls das XmlRoot-Attribute hinzufüge, und noch das XmlSerializerNamespaces Objekt mit den zusätzlichen Namespace befülle, ist es nur unwesentlich besser.
Woran liegt das, dass eine Abgeleitete Klasse soviel Probleme bereitet?


  <?xml version="1.0" ?> 
- <s:Station xmlns:m="http://Modul" xmlns:b="http://Base" xmlns:c="http://Controller" xmlns:d="http://Device" xmlns:s="http://Station">
  - <s:Controller>
      <b:Name>ConName</c:Name> 
      <b:Address1 d3p1:nil="true" xmlns:d3p1="http://www.w3.org/2001/XMLSchema-instance" /> 
      <b:IpAddress>192.168.1.1</c:IpAddress> 
    </s:Controller>
  </s:Station>

Gruß,
IchRoque81

~ rock on ~

4.939 Beiträge seit 2008
vor 13 Jahren

Hallo nochmal,

es scheint wohl eher ein Problem mit Address1, d.h. 'byte?' zu bestehen, denn 'Name' und 'IPAddress' funktioniert ja.
Was soll denn in diesem Feld gespeichert werden, d.h. warum 'byte?' und nicht einfach nur 'byte' ???

IchRoque81 Themenstarter:in
36 Beiträge seit 2008
vor 13 Jahren

Hallo!

In dem Feld soll ein Adresswert, der zwischen 0 und x liegt, gespeichert werden. Jedoch wird vom Benutzer nicht verlangt, dass er einen Wert eingibt. Soll also optional sein, deshalb auch byte? damit auch Null erlaubt ist.

Int scheidet deshalb leider aus, weil der default-Wert ja 0 ist, und das auch im gültigem Bereich liegt ?(

~ rock on ~

4.939 Beiträge seit 2008
vor 13 Jahren

Hast du denn mal getestet, ob es einfach nur mit "byte" funktioniert?
Du könntest dann ja "sbyte" nehmen und -1 als "ohne Benutzereingabe" interpretieren
(bzw. short/int falls dein x > 127 / 32767).

Um den Standardwert zu setzen, brauchst du einfach einen Konstruktor hinzufügen:


public abstract class Base
{
     public Base()
     {
         Address1 = -1;
     }

     // ...
}

Leider unterstützt C# keine Defaultzuweisung bei automatischen Eigenschaften à la


public byte? Address1 { get; set; } = -1;

sondern alternativ müßte man dann selber wieder ein privates Feld anlegen und von der Eigenschaft dann darauf zugreifen...

IchRoque81 Themenstarter:in
36 Beiträge seit 2008
vor 13 Jahren

Hi Th69,

hab noch ne bessere Lösung gefunden. Einfach noch einen weiteren Namespace hinzufügen und schon siehts aus, wie zuvor =)


XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
ns.Add("xsi", "http://www.w3.org/2001/XMLSchema-instance");

~ rock on ~