[C#] Xml serialization met abstracte classes

Pagina: 1
Acties:

  • _Thanatos_
  • Registratie: Januari 2001
  • Laatst online: 23-12-2025

_Thanatos_

Ja, en kaal

Topicstarter
Beetje vreemde titel, maar het komt hierop neer: ik wil descendants van een abstracte class serializen naar XML, zonder dat dat <Base xs:type="Descendant"> nodes oplevert. Ik heb de volgende code (gesimplificeerd):
C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
[Serializable]
public class Container {
   [XmlArray("Items")]
   [XmlArrayItem("Item")]
   public BaseClass[] Items;
}

public abstract class BaseClass { }

[XmlRoot("Descendant1")]
public class Descendant1: BaseClass { }

[XmlRoot("Descendant2")]
public class Descendant1: BaseClass { }


Ik zou hieruit verwachten dat de deserializer de volgende XML wel slikt:
XML:
1
2
3
4
5
6
7
<Container>
  <Items>
    <Descendant1 />
    <Descendant1 />
    <Descendant2 />
  </Items>
</Container>

Maar helaas, in plaats van <Descendant1/> moet hij per se <Item xs:type="Descendant1"/> hebben. Ondanks het feit dat ik met [XmlRoot] toch al aangeef hoe het element moet gaan heten... Nou kun je zeggen dat dat door [XmlArrayItem] komt, maar als ik die weglaat, blijven die xs:type attributen verplicht.

De vraag is dus hoe ik kan aangeven van de *naam van het element* aangeeft welke class het item in de array moet worden, ipv het xs:type attribuut...

Heeft iemand enige ideeën of aanwijzingen hoe ik de XML krijg zoals ik em wil?

日本!🎌


  • Vedett.
  • Registratie: November 2005
  • Laatst online: 08:13
Volgens mij gaat dit helemaal niet lukken.
Je kan nooit in je naam aangeven welk type er verwacht wordt. Je zult altijd in een xsd moeten specifiëren wat voor type een bepaald element kan bevatten.

Wat wil je eigenlijk bereiken? Want ik vermoed dat je een workaround zoekt voor iets.


Heb even een xsd schema gegenereerd met jouw code. Je zult altijd het type-attribuut moeten gebruiken. Het voordeel om het via een xsd-schema te doen, is dat je het maar één keer hoeft te specifiëren.

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<?xml version="1.0" encoding="utf-8"?>
<xs:schema elementFormDefault="qualified" targetNamespace="http://test/base" xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:element name="Container" nillable="true" type="Container" />
  <xs:complexType name="Container">
    <xs:sequence>
      <xs:element minOccurs="0" maxOccurs="1" name="Items" type="ArrayOfBaseClass" />
    </xs:sequence>
  </xs:complexType>
  <xs:complexType name="ArrayOfBaseClass">
    <xs:sequence>
      <xs:element minOccurs="0" maxOccurs="unbounded" name="Item" nillable="true" type="BaseClass" />
    </xs:sequence>
  </xs:complexType>
  <xs:complexType name="BaseClass" abstract="true" />
  <xs:element name="BaseClass" nillable="true" type="BaseClass" />
  <xs:element name="Descendant1" nillable="true" type="Descendant1" />
  <xs:complexType name="Descendant1">
    <xs:complexContent mixed="false">
      <xs:extension base="BaseClass" />
    </xs:complexContent>
  </xs:complexType>
  <xs:element name="Descendant2" nillable="true" type="Descendant2" />
  <xs:complexType name="Descendant2">
    <xs:complexContent mixed="false">
      <xs:extension base="BaseClass" />
    </xs:complexContent>
  </xs:complexType>
</xs:schema>

[ Voor 71% gewijzigd door Vedett. op 18-09-2006 21:19 ]


  • _Thanatos_
  • Registratie: Januari 2001
  • Laatst online: 23-12-2025

_Thanatos_

Ja, en kaal

Topicstarter
Begrijp ik het goed dat je met dat schema definieert welk element welk onderliggend type is? Dan heb ik dat xs:type attribuut niet meer nodig?

Het gaat er dus om dat de gebruiker (gericht op advanced gebruikers) de XML kunnen editten. Dan vindt ik die xs:type attributen met daarin het .NET type als waarde, ronduit slordig. Ik wil er een beter naampje aan geven, en in elk geval die ingewikkelde xs:type weg hebben. Dat snapt toch niemand.

In de web.config (of app.config) kun je tenslotte ook meerdere verschillende elementen in een array stoppen (bijv die add/remove/clear elementjes). Niet dat het zoiets moet worden, maar ik geef maar ff aan dat het daar wel kan, dus wat ik wil zou ook moeten kunnen.

Nu nog de vraag hoe ik dan deserialize met een schema. Want noch de XmlSerializer constructor, noch een van z'n properties, noch de Deserialize methode kan ik een schema in stopen :?

日本!🎌


  • Vedett.
  • Registratie: November 2005
  • Laatst online: 08:13
Heel simpel eigenlijk.

Je maakt een xsd aan. In die xsd specifieer je waaraan een xml document moet voldoen zodat het nog steeds geldige xml is binnen je toepassing. Vervolgens genereer je met xsd.exe (in de command line tools van visual studio) je classes.

Nu kan je xml documenten inlezen in een, jawel XmlDocument van .Net. Nu kan je deserializeren en je hebt werkbare classes.

Maar begrijp ik het goed dat als jij element A specifieert in je xsd, en één gebruiker heeft liever B, dat die dan B kan nemen?? Dat gaat volgens mij niet lukken. Ik weet niet of er zoiets als een alias bestaat in xml/xsd.

Ben je bezig met een webservice? Zoja, zou je eens kunnen googelen op Contract First development. Ik weet dat er bij www.thinktecture.com daar wel wat over te vinden is.

  • _Thanatos_
  • Registratie: Januari 2001
  • Laatst online: 23-12-2025

_Thanatos_

Ja, en kaal

Topicstarter
Nee, het is gewoon een array waarin meerdere types van 1 basistype voor kunnen komen.

En nee, geen webservice. Gewoon een console app ;)

日本!🎌


  • Vedett.
  • Registratie: November 2005
  • Laatst online: 08:13
Het principe blijft hetzelfde eigenlijk. Webservice of niet. Je wilt een array met meerdere types van 1 basistype serializeren. Zolang je de xml valid houd met de xsd is er geen enkel probleem.

Wat me nu wel opvalt is dat je geen namespaces hebt. Die zou op zowel je type als in je xsd hetzelfde moeten zijn volgens mij. Dus probeer eerst eens een xsd te maken waarin je de structuur van je xml vast legt. Die xsd gebruik je dan om classes te genereren. Bij het serializeren heb je die xsd dan niet meer nodig.

  • _Thanatos_
  • Registratie: Januari 2001
  • Laatst online: 23-12-2025

_Thanatos_

Ja, en kaal

Topicstarter
Dat heb ik geprobeerd, maar die subclasses "Descendant1" en "Descendant2" dus in mijn voorbeeld, moet ik dan in het schema gaan definieren, terwijl ik ze in m'n code heb gedefiniëerd. Bovendien, de gegenereerde classes gaan dan 2 arrays krijgen; een van het type Descendant1[] en een van het type Descendant2[]. En dat terwijl ik juist 1 array wil, en niet 2 die ook nog es hun types vastgelegd hebben. Straks heb ik 15 soorten descendants en dus aparte 15 arrays.

日本!🎌


  • Vedett.
  • Registratie: November 2005
  • Laatst online: 08:13
Ik geloof dat ik nu door heb wat je wilt 8)7 (beter laat dan nooit zeker??)

Maar dat gaat niet lukken tenzij je met custom serialization aan de slag gaat.
Kijk eens naar het XmlSchemaProviderAttribute. Of google even en je vind http://weblogs.asp.net/cweyer/archive/2004/08/02/205798.aspx en http://www.codeproject.com/soap/XmlSchemaProvider.asp

Je zult wel extra logica moeten inbouwen want de voorbeelden in deze artikels zijn nog redelijk simpel vergeleken met wat jij wilt.

Maak er een mooie class van en mail maar door :9. Ik kan hier misschien ook wel iets mee.
Pagina: 1