2

I have a problem about deserialize an array. Becouse array elements can be of various types. You can see the example:

<?xml version="1.0" encoding="UTF-8"?><export xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://zakupki.gov.ru/oos/export/1" xmlns:oos="http://zakupki.gov.ru/oos/types/1">
<notificationZK>
    ... item 1 data
</notificationZK>
<notificationZK>
    ... item 2 data
</notificationZK>
<notificationFF>
    ... item 3 data
</notificationFF>
</export>

All elements extends notificationType

   [System.Xml.Serialization.XmlIncludeAttribute(typeof(notificationSZType))]
    [System.Xml.Serialization.XmlIncludeAttribute(typeof(notificationPOType))]
    [System.Xml.Serialization.XmlIncludeAttribute(typeof(notificationZKType))]
    [System.Xml.Serialization.XmlIncludeAttribute(typeof(notificationEFType))]
    [System.Xml.Serialization.XmlIncludeAttribute(typeof(notificationOKType))]
    public partial class notificationType
    {
...

So the question is how can I get the collection of notificationType elements from my XML file? I think I cant do something like

[Serializable()]
[System.Xml.Serialization.XmlRoot("export")]
public class NotificationCollection
{
    [XmlArray("")] // ???? what I need write here?
    [XmlArrayItem("", typeof(notificationType))] // ??? and here?
    public notificationType[] notification { get; set; }
}

Regards!

ADDED-------------

So. I make this:

[Serializable()]
[System.Xml.Serialization.XmlRoot("export")]
public class NotificationCollection
{
    [XmlElement("notificationSZType", Type = typeof(notificationSZType))]
    [XmlElement("notificationPOType", Type = typeof(notificationPOType))]
    [XmlElement("notificationZKType", Type = typeof(notificationZKType))]
    [XmlElement("notificationEFType", Type = typeof(notificationEFType))]
    [XmlElement("notificationOKType", Type = typeof(notificationOKType))]
    public notificationType[] notification { get; set; }
}

class Program
{
    static void Main(string[] args)
    {
        NotificationCollection collection = null;
        string path = @"E:\notification.xml";
        XmlSerializer serializer = new XmlSerializer(typeof(notificationType));
        StreamReader reader = new StreamReader(path);
        collection = (NotificationCollection) serializer.Deserialize(reader);
        reader.Close();

    }
}

but have System.InvalidOperationException was unhandled while serializer.Deserialize(reader);

Message=<export xmlns='http://zakupki.gov.ru/oos/export/1'> not expected.

What im doing wrong?

5
  • The example XML is missing the opening <export> tag. Commented Sep 5, 2013 at 8:31
  • Why its missing? Its the real XML from project I working :( Here is the example of real file: sendspace.com/file/u5bfs7 Commented Sep 5, 2013 at 8:40
  • Ignore me. I misread :( Commented Sep 5, 2013 at 8:41
  • I've tested 3 of your answers and they work. Commented Sep 5, 2013 at 9:21
  • But it not work for me :( I generated C# classes from XSD. XSD can be downloaded here zakupki.gov.ru/epz/main/public/download/… Possible generated classes are missing? Commented Sep 5, 2013 at 9:29

3 Answers 3

2

How about moving the type declarations into the collection?

[XmlRoot("export")]
public class NotificationCollection
{

  [XmlElement("notificationZK", typeof(NotificationTypeZK))]
  [XmlElement("notificationFF", typeof(NotificationTypeFF))]
  public List<NotificationType> Notifications { get; set; }

}

public class NotificationType
{

}

public class NotificationTypeZK : NotificationType { }

public class NotificationTypeFF : NotificationType { }

static void Main(string[] args)
{
  var data = @"<export><notificationZK /><notificationZK /><notificationFF /></export>";

  var serializer = new XmlSerializer(typeof(NotificationCollection));

  using (var reader = new StringReader(data))
  {
    var notifications = serializer.Deserialize(reader);
  }
}
Sign up to request clarification or add additional context in comments.

Comments

1

This should do the job

    [Serializable()]
    [System.Xml.Serialization.XmlRoot("export")]
    public class NotificationCollection
    {
        [XmlElement("notificationSZType", Type = typeof(notificationSZType))]
        [XmlElement("notificationPOType", Type = typeof(notificationPOType))]
        [XmlElement("notificationZKType", Type = typeof(notificationZKType))]
        [XmlElement("notificationEFType", Type = typeof(notificationEFType))]
        [XmlElement("notificationOKType", Type = typeof(notificationOKType))]
        public notificationType[] notification { get; set; }
    }

2 Comments

@Gusdor how do i implement this if the elements are unknown? in OP's case, the elements' names are known. in my case i can't do [XmlElement("notificationOKType", Type = typeof(notificationOKType))] public notificationType[] notification { get; set; } because the element 'notificationOKType' could have any name
@wintersolstice this is possible (and straight forward) but you should create another question.
0

This question is interesting for me as well. I wrote the simplified app to achieve what you ask for:

[Serializable]
[XmlInclude(typeof(ItemA))]
[XmlInclude(typeof(ItemB))]
public class BaseItem
{
    public bool Value { get; set; }
}

[Serializable]
public class ItemA : BaseItem
{
    public string Text { get; set; }
}

[Serializable]
public class ItemB : BaseItem
{
    public int Number { get; set; }
}

[Serializable]
public class ItemsArray
{
    public BaseItem[] Items { get; set; }
}

class Program
{
    static void Main(string[] args)
    {
        var array = new ItemsArray
        {
            Items = new BaseItem[]
            {
                new ItemA { Value = true, Text = "Test" },
                new ItemB { Value = false, Number = 7 }
            }
        };

        ItemsArray output;

        using (var stream = new MemoryStream())
        {
            var serializer = new XmlSerializer(typeof(ItemsArray));
            serializer.Serialize(stream, array);

            stream.Position = 0;
            output = (ItemsArray)serializer.Deserialize(stream);
        }
    }
}

After deserialization we get exactly what we serialized. The XML inside stream looks like:

<?xml version="1.0"?>
<ItemsArray xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Items>
    <BaseItem xsi:type="ItemA">
      <Value>true</Value>
      <Text>Test</Text>
    </BaseItem>
    <BaseItem xsi:type="ItemB">
      <Value>false</Value>
      <Number>7</Number>
    </BaseItem>
  </Items>
</ItemsArray>

As was mentioned in other answer, you can't use different tags inside XML array. However, it's still possible to store different types. Serializer does this by using xsi:type attribute.

In order to solve your problem you probably need to use a bit another scheme of XML.

2 Comments

If the format of the export isn't fixed, I'd use such an approach as well.
Depending on your schema, it is valid XML to have varying child element tag names. It is possible to solve this problem while retaining the schema defined in the question.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.