1
votes

I use C# to deserialize a XML file. My XML file has the format:

<Produced_by >
    <Producing_Unit>
        <Unit ID="" Name=""/>
    </Producing_Unit>
</Produced_by>

When deserializing I want to remove the middleman Producing_Unit. Since Produced_by will always contain only one subelement Producing_Unit specifying the Unit. My initial thoughts on how to implement doesn't work:

public class Unit
{
    public string Name { get; set; }
    public string ID { get; set; }
}

public class Produced_by
{
    [XmlElement("Producing_Unit")]
    [XmlElement("Unit")]
    public Unit Unit { get; set; }
}

It could be soleved by using [XmlArray("Producing_Unit"), XmlArrayItem("Unit")] and then having Produced_by contain: public List<Unit> {get;set;}. But that's not what I want.

2
Try putting the XMLElement properties in the Unit class, and above it's properties. - Ramie
AFAIK, it's not possible to use the XML with the "Producing_Unit" tag but ditch the matching Producing_Unit class with the standard attributes short of implementing the IXmlSerializable interface. Your best bet would be to separate your application/business logic from your serialization layer. Keep your serialization simple and matching your XML schema, then simply convert to/from that data model and a cleaner data model (without Producing_Unit) for the rest of your application to work with. - Chris Sinclair
@Ramie Could you give me an example of this? - bjar-bjar

2 Answers

0
votes

As far as I know, it's not possible to use the XML with the "Producing_Unit" tag but ditch the matching Producing_Unit class with the standard attributes short of implementing the IXmlSerializable interface. Your best bet would be to separate your application/business logic from your serialization layer.

Keep your serialization data model simple and matching your XML schema (this means including the wrapping Producing_Unit class), then simply convert to/from that data model and a cleaner data model (without Producing_Unit) for the rest of your application to work with.


EDIT: Here's an implementation using the IXmlSerializable interface. I just whipped it off and honestly, don't know if it will work for all cases.

public class Unit
{
    public string Name { get; set; }

    public string ID { get; set; }
}

public class Produced_by : IXmlSerializable
{
    public Unit Unit { get; set; }

    public void WriteXml (XmlWriter writer)
    {
        writer.WriteStartElement("Produced_by");
        writer.WriteStartElement("Producing_Unit");
        writer.WriteStartElement("Unit");
        writer.WriteAttributeString("ID", this.Unit.ID);
        writer.WriteAttributeString("Name", this.Unit.Name);
        writer.WriteEndElement();
        writer.WriteEndElement();
        writer.WriteEndElement();
    }

    public void ReadXml (XmlReader reader)
    {
        while (reader.Read())
        {
            if (reader.Name == "Unit")
            {
                this.Unit = new Unit()
                {
                    Name = reader.GetAttribute("Name"),
                    ID = reader.GetAttribute("ID")
                };

                break;
            }
        }
    }

    public XmlSchema GetSchema()
    {
        return(null);
    }
}

I suspect that I'm performing the reading in a poor fashion, but this works in my local test. I still recommend separating your application and serialization concerns though and avoiding having to write an implementation like this.

0
votes

You could try this:

public class Unit
{
    public string Name { get; set; }
    public string ID { get; set; }
}

public class Producing_Unit
{
    public Unit Unit { get; set; }
}

public class Produced_by
{
    private Producing_Unit producing_unit;

    public Producing_Unit Producing_Unit //This can't be auto-implemented since can write to properties of properties.
    { 
        get { return producing_Unit; } 
        set { producing_Unit = value; }
    }

    [XmlIgnoreAttribute]
    public Unit Unit
    {
        get { return producing_Unit.Unit; }
        set { producing_Unit.Unit = value; }
    }
}

Yes, it doesn't get rid of the 'middle-men,' but you can ignore them.