0

Suppose I am trying to deserialize the following XML (in a C# program):

<Data>
    <DataItem Id="1" Attrib1="Val1_1" Attrib2="Val2_1" Attrib3="Val3_1" />
    <DataItem Id="2" Attrib1="Val1_2" Attrib4="Val4_2" />
    <DataItem Id="3" Attrib3="Val3_1" Attrib5="Val5_3" />
</Data>

So, each DataItem element will have an Id field and a random set of attributes I'd like to capture / store.

I'm imagining the final containing classes could look as follows:

[XmlRootAttribute("Data")]
public class Data
{
    [XmlElement("DataItem")]
    public DataItem[] Items { get; set; }
}

public class DataItem
{
    public Dictionary<string, object> Vals { get; set; }

    [XmlIgnore]
    public string Id { get { return (string)Vals[Id]; } }
}

(If I'm wrong on this structure, PLEASE let me know - this is still all very new to me!!)

But I'm not sure how to deserialize the attributes into the [Key][Value] pairs for my dictionary. I found this question and also this other answer that seem to be pointing me in the right (albeit different) directions, but I'm lost in how to implement this correctly and know this should be fairly easy.

Any help / links / samples on how this could be done would be GREATLY appreciated!!

Thanks!!!

Community
  • 1
  • 1
John Bustos
  • 19,036
  • 17
  • 89
  • 151
  • 2
    There's no way you're going to do this with attributes. You'll need to implement `IXmlSerializable` and manually write the serialization code for `DataItem`. – Charles Mager Jul 08 '15 at 14:52

3 Answers3

1

A more generic solution would be:

public class DynamicAttributes : IXmlSerializable, IDictionary<string, object>
{
    private readonly Dictionary<string, object> _attributes;

    public DynamicAttributes()
    {
        _attributes = new Dictionary<string, object>();
    }

    public XmlSchema GetSchema()
    {
        return null;
    }

    public void ReadXml(XmlReader reader)
    {
        if (reader.HasAttributes)
        {
            while (reader.MoveToNextAttribute())
            {
                var key = reader.LocalName;
                var value = reader.Value;

                _attributes.Add(key, value);
            }

            // back to the owner of attributes
            reader.MoveToElement();
        }

        reader.ReadStartElement();
    }

    public void WriteXml(XmlWriter writer)
    {
        foreach (var attribute in _attributes)
        {
            writer.WriteStartAttribute(attribute.Key);

            writer.WriteValue(attribute.Value);

            writer.WriteEndAttribute();
        }
    }

    // implementation of IDictionary<string, object> comes here
}

Than the classes for your case would be:

[XmlRoot("Data")]
public class Data
{
    [XmlElement("DataItem")]
    public DataItem[] Items { get; set; }
}

public class DataItem : DynamicAttributes
{
    [XmlIgnore]
    public string Id
    { 
        get
        {                
            return this.TryGetValue("Id", out var value) ? value.ToString() : null;
        } 
    }
}
0

Ok, so as I suspected (and was suggested in the comments), I left aside direct XML serialization and wrote my own parsing method to accomplish this.

For anyone else this may help, here's what I ended up writing - Hope it helps you too (If anyone has a better answer, though, PLEASE do post it! - I'd love to see how else this could be accomplished / done better):

public class Data
{
    public List<DataItem> Items { get; set; }

    private Data(XElement root)
    {
        Items = new List<DataItem>();

        foreach (XElement el in root.Elements())
        {
            Items.Add(new DataItem(el));
        }
    }

    public static Data Load(Stream stream)
    {
        return new Data(XDocument.Load(stream).Root);
    }
}

public class DataItem
{
    public Dictionary<string, string> Vals;
    public string Id { get { return (string)Vals["Id"]; } }

    public DataItem(XElement el)
        {
            Vals = new Dictionary<string, string>();

            // Load all the element attributes into the Attributes Dictionary
            foreach (XAttribute att in el.Attributes())
            {
                string name = att.Name.ToString();
                string val = att.Value;

                Vals.Add(name, val);
            }
        }
}

Then it would be used in code fairly simply via:

Data MyData = Data.Load(MyXMLStream);

Hope this helps others too!!

John Bustos
  • 19,036
  • 17
  • 89
  • 151
-3

Use This

<Data>
    <DataItem Id="1" Val="Val1_1" />
    <DataItem Id="1" Val="Val2_1" />
    <DataItem Id="1" Val="Val3_1" />
    <DataItem Id="2" Val="Val1_2" />
    <DataItem Id="2" Val="Val4_2" />
    <DataItem Id="3" Val="Val3_1" />
    <DataItem Id="3" Val="Val5_3" />
</Data>
jdweng
  • 33,250
  • 2
  • 15
  • 20
  • Sorry, @jdweng, that doesn't even make sense to me.... The XML is given, I'm asking how to de-serialize it to a dictionary.... – John Bustos Jul 08 '15 at 16:44