0
votes

Today I got updated XML content from the 3rd-party backend and had to change our XmlSerializer-based parsing code just to comply with new fields. Unfortunately, I figured out that there was introduced a collection of similar tags but with weird behavior:

<old-root>
  ...
  <contacts>
    <John>Feel happy</John>
    <Mary>Will be away for 2 hours, phone me</Mary>
    <Bob>Do not disturb. I mean it!</Bob>
    ...and so on...
  </contacts>
</root>

So far we had a parser class for "old-root" based on [XmlElement] mappings but I didn't figure out yet how to manage a collection of that similar name-value pairs via XML annotations (something like [XmlArray]/[XmlArrayItem] usually does). I can get a value via [XmlText] annotation but how to annotate that any-tag? "Star" pattern has no effect for ElementName.

P.S. I'm on UWP subset of .NET framework.

1
Are the nodes <John>, <Mary>, <Bob> known at design time? Or are they arbitrary nodes?JuanR
@Juan, exact names are not known at design time. It's kind of contacts list you receive from the backend.Yury Schkatula
Then your strategy of using attributes no longer suffices. I think you are beyond basic serialization so you will have to implement a custom serializer/deserializer.JuanR

1 Answers

1
votes

I can suggest the following approach. Use dictionary for your different tags. XmlSerializer can't work with a dictionary, so mark it with the XmlIgnore attribute and deserialize data manually.

[XmlRoot("old-root")]
public class Root
{
    [XmlIgnore]
    public Dictionary<string, string> Contacts { get; set; }
}

First read the xml into an XElement and create a dictionary from a node contacts. Delete that node. Then deserialize data from this XElement. At the end set the previously created dictionary.

var xs = new XmlSerializer(typeof(Root));
Root root = null;
StorageFolder folder = ApplicationData.Current.LocalFolder;

using (var stream = await folder.OpenStreamForReadAsync("test.xml"))
{
    var xml = XElement.Load(stream);
    var contacts = xml.Element("contacts");
    var dict = contacts.Elements().ToDictionary(x => x.Name.LocalName, x => x.Value);
    contacts.Remove();

    root = (Root)xs.Deserialize(xml.CreateReader());
    root.Contacts = dict;
}

It's pretty ugly, because it is inefficient both from the memory consumption point of view and performance point of view. But it's simply and briefly.