Check alle échte Black Friday-deals Ook zo moe van nepaanbiedingen? Wij laten alleen échte deals zien

[.NET]XML Serialization met Generic Custom Collection

Pagina: 1
Acties:

  • Woy
  • Registratie: April 2000
  • Niet online

Woy

Moderator Devschuur®
Topicstarter
Ik ben bezig met het (de)serializeren van xml in .NET. Nu heb ik een groot aantal documenten met verschillende collecties die eigenlijk exact hetzelfde zijn, behalve het type van de elementen die er in zitten.

Ik probeer bijvoorbeeld de volgende XML te serializeren
XML:
1
2
3
4
5
6
7
8
9
10
<?xml version="1.0" encoding="utf-16"?>
<response xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" errorcode="1">
  <foos count="1">
    <foo>Foo1</foo>
  </foos>
  <bars count="2">
    <bar>Bar1</bar>
    <bar>Bar2</bar>
  </bars>
</response>

Dat krijg ik op zich prima voor elkaar met de volgende definitie
C#:
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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
[XmlRoot("response")]
public class Response
{
    [XmlAttribute("errorcode")]
    public int ErrorCode { get; set; }

    [XmlElement("foos")]
    public FooCollection Foos { get; set; }

    [XmlElement("bars")]
    public BarCollection Bars { get; set; }
}

public class FooCollection
{
    [XmlAttribute("count")]
    public int Count { get; set; }

    [XmlElement("foo")]
    public Foo[] Foos { get; set; }
}

public class BarCollection
{
    [XmlAttribute("count")]
    public int Count { get; set; }

    [XmlElement("bar")]
    public Bar[] Bars { get; set; }
}

public class Foo
{
    [XmlText]
    public string Value { get; set; }
}

public class Bar
{
    [XmlText]
    public string Value { get; set; }
}

Echter is het nogal veel werk om voor alle collecties een custom type te gaan definieren. Ik zou liever een generieke collectie maken waar ik dan met generics aangeef welk type ik gebruik. Eigenlijk net zoals ik met XmlArray en XmlArrayItem kan doen
C#:
1
2
[XmlArray("foos"), XmlArrayItem("foo")]
public Foo[] Foos { get; set; }

Het probleem daarbij is dat ik weer geen extra ( generieke ) properties bij de collectie toe kan voegen.

Is er een manier waarop ik bijvoorbeeld de volgende collectie kan serializeren, waarbij ik bij het gebruik aan kan geven welk type en tagname er gebruikt wordt?
C#:
1
2
3
4
5
6
7
public class MyCollection<T>
{
    [XmlAttribute("count")]
    public int Count { get; set; }
    
    public T[] Items { get; set; }
}

“Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.”


  • Alex)
  • Registratie: Juni 2003
  • Laatst online: 18-11 20:57
Ik denk dat dat niet kan zonder zelf de serialisatie te implementeren. Dat kan door IXmlSerializable te implementeren.

MSDN: IXmlSerializable Interface (System.Xml.Serialization)

We are shaping the future


  • Haan
  • Registratie: Februari 2004
  • Laatst online: 16:52

Haan

dotnetter

Wat ik sowieso doe als ik iets met XML moet doen in code, is eerst een XSD van de XML genereren, en vervolgens de classes genereren vanuit die XSD (met xsd.exe).
Met een XmlSerializer en XmlReader kan je vervolgens het spul dan deserializen naar je gegenereerde classes.

Kater? Eerst water, de rest komt later


Verwijderd

Ik denk dat dit de oplossing is voor hetgeen je wil: http://stackoverflow.com/...ialize-collections-in-net

ik heb het ook maar gegoogled

  • Woy
  • Registratie: April 2000
  • Niet online

Woy

Moderator Devschuur®
Topicstarter
Alex) schreef op woensdag 06 februari 2013 @ 10:37:
Ik denk dat dat niet kan zonder zelf de serialisatie te implementeren. Dat kan door IXmlSerializable te implementeren.

MSDN: IXmlSerializable Interface (System.Xml.Serialization)
Ja het nadeel is dat je dan weer zelf moet gaan serializen, maar op zich zou je daar wel weer wat generieks mee kunnen maken.
Haan schreef op woensdag 06 februari 2013 @ 10:44:
Wat ik sowieso doe als ik iets met XML moet doen in code, is eerst een XSD van de XML genereren, en vervolgens de classes genereren vanuit die XSD (met xsd.exe).
Met een XmlSerializer en XmlReader kan je vervolgens het spul dan deserializen naar je gegenereerde classes.
Het punt is dat ik juist via de code snel wijzigingen wil kunnen doorvoeren want het gaat over een test projectje, door de extra stap met xsd en code generatie wordt dat toch wat minder handig.
Verwijderd schreef op donderdag 07 februari 2013 @ 08:06:
Ik denk dat dit de oplossing is voor hetgeen je wil: http://stackoverflow.com/...ialize-collections-in-net

ik heb het ook maar gegoogled
Dit is feitenlijk ongeveer hetzelfde als het voorbeeld dat ik geef. Het punt is dat ik dan geen controle heb over wat de tagname van de elementen is, behalve als ik weer voor elk type een aparte class maak. Het punt is ook niet dat ik niet weet hoe ik het moet (de)serializen, maar dat ik een generiekere manier zoek, om zo werk/code te besparen.

“Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.”


  • pedorus
  • Registratie: Januari 2008
  • Niet online
Woy schreef op woensdag 06 februari 2013 @ 09:06:
Eigenlijk net zoals ik met XmlArray en XmlArrayItem kan doen
C#:
1
2
[XmlArray("foos"), XmlArrayItem("foo")]
public Foo[] Foos { get; set; }

Het probleem daarbij is dat ik weer geen extra ( generieke ) properties bij de collectie toe kan voegen.
Dit gaat waarschijnlijk nooit lukken (tenzij je dit zelf implementeert in een klasse met eigen serialisatie). Collecties kunnen vooralsnog geen XML attributes bevatten. XML attributen zijn sowieso trouwens onhandig, DataContract doet er dan ook niet aan. Dit attribuut count is zelfs volledig redundant.

Wat natuurlijk wel kan, zoals al gezegd met IXmlSerializable; als ik even wat code uit archief aanpas:
C#:
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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
public class MyCollection<T> : IXmlSerializable
{
    public T[] Items { get; set; }

    public System.Xml.Schema.XmlSchema GetSchema()
    {
        return null;
    }

    public void ReadXml(System.Xml.XmlReader reader)
    {
        reader.MoveToContent();
        var isEmptyElement = reader.IsEmptyElement;
        reader.ReadStartElement();
        var list = new List<T>();
        if (!isEmptyElement)
        {
            var name = typeof(T).Name.ToLowerInvariant();
            var root = new XmlRootAttribute(name);
            var serializer = new XmlSerializer(typeof(T), root);
            while (reader.NodeType != System.Xml.XmlNodeType.EndElement)
            {
                if (reader.IsStartElement(name))
                {
                    list.Add((T)serializer.Deserialize(reader));
                }
                else
                {
                    reader.Skip();
                }
            }
            reader.ReadEndElement();
        }
        Items = list.ToArray();
    }

    public void WriteXml(System.Xml.XmlWriter writer)
    {
        writer.WriteAttributeString("count", Items.Length.ToString());
        var name = typeof(T).Name.ToLowerInvariant();
        var root = new XmlRootAttribute(name);
        var serializer = new XmlSerializer(typeof(T), root);
        foreach (var item in Items)
        {
            serializer.Serialize(writer, item);
        }
    }
}

Blijft een verschrikking, geen vrienden met die XmlReader ;) Dus gewoon die count weghalen :Y)

Vitamine D tekorten in Nederland | Dodelijk coronaforum gesloten

Pagina: 1