Unknown XML Custom Serialization

I am trying to deserialize a custom class through an XmlSerializer and have several problems in that I don’t know the type that I am going to deserialize (it connects) and I am having difficulty defining it.

I found this post that looks similar, but cannot make it work with my approach, because I need to deserialize the interface, which is XmlSerializable.

What I have takes shape. Please note that I expect and should be able to handle both class A and class B, which will be implemented through the plugin. Therefore, if I can avoid using IXmlSerializable (which I think I cannot), that would be great.

ReadXml for A is what I'm stuck with. However, if there are other changes that I can make to improve the system, I will be happy to do so.

public class A : IXmlSerializable
{
   public IB MyB { get; set;}

   public void ReadXml(System.Xml.XmlReader reader)
   {
      // deserialize other member attributes

      SeekElement(reader, "MyB");
      string typeName = reader.GetAttribute("Type");

      // Somehow need to the type based on the typename. From potentially 
      //an external assembly. Is it possible to use the extra types passed 
      //into an XMlSerializer Constructor???
      Type bType = ???

      // Somehow then need to deserialize B Members
      // Deserialize X
      // Deserialize Y
   }

   public void WriteXml(System.Xml.XmlWriter writer)
   {
      // serialize other members as attributes

      writer.WriteStartElement("MyB");
      writer.WriteAttributeString("Type", this.MyB.GetType().ToString());
      this.MyB.WriteXml(writer);
      writer.WriteEndElement();
   }

   private void SeekElement(XmlReader reader, string elementName)
   {
      ReaderToNextNode(reader);
      while (reader.Name != elementName)
      {
         ReaderToNextNode(reader);
      }
   }

   private void ReaderToNextNode(XmlReader reader)
   {
      reader.Read();
      while (reader.NodeType == XmlNodeType.Whitespace)
      {
         reader.Read();
      }
   }
}

public interface IB : IXmlSerializable
{
}

public class B : IB
{

     public void ReadXml(XmlReader reader)
     {
         this.X = Convert.ToDouble(reader.GetAttribute("x"));
         this.Y = Convert.ToDouble(reader.GetAttribute("y"));
     }

   public void WriteXml(XmlWriter writer)
   {
      writer.WriteAttributeString("x", this.X.ToString());
      writer.WriteAttributeString("y", this.Y.ToString());
   }
}

NOTE. Updated as I realized that B had to use the IB interface. Sorry for the wrong question.

+3
source share
3 answers

To create an instance from a string, use one of the Activator.CreateInstance overloads. To simply get a type with this name, use Type.GetType.

+3
source

I do not think you need to implement IXmlSerializable...

, XmlSerializer. , A. , A :

public class SomeClass
{
    public A SomeProperty { get; set; }
}

XmlElementAttribute :

XmlAttributes attr = new XmlAttributes();
var candidateTypes = from t in AppDomain.CurrentDomain.GetAssemblies().SelectMany(a => a.GetTypes())
                     where typeof(A).IsAssignableFrom(t) && !t.IsAbstract
                     select t;
foreach(Type t in candidateTypes)
{
    attr.XmlElements.Add(new XmlElementAttribute(t.Name, t));
}

XmlAttributeOverrides overrides = new XmlAttributeOverrides();
overrides.Add(typeof(SomeClass), "SomeProperty", attr);

XmlSerializer xs = new XmlSerializer(typeof(SomeClass), overrides);
...

, , XML , .

+1

xpath, , xml A B. .

0

Source: https://habr.com/ru/post/1711757/


All Articles