0

I have already tried various possibilities but maybe I am just too tired of seeing the solution -.-

I have an xml structure like this:

<diagnosisList>
  <diagnosis>
    <surgery1>
        <date>1957-08-13</date>
        <description>a</description>
        <ops301>0-000</ops301>
    </surgery1>
    <surgery2>
        <date>1957-08-13</date>
        <description>a</description>
        <ops301>0-000</ops301>
    </surgery2>
    <surgery...>
    </surgery...>
  </diagnosis>
</diagnosisList>

As you see there is a variable number of surgeries. I have a class "surgery" containing the XML elements.

class Surgery
    {
        [XmlElement("date")]
        public string date { get; set; }

        [XmlElement("description")]
        public string description { get; set; }

        [XmlElement("ops301")]
        public string ops301 { get; set; }

        public Surgery()
        {
        }
    }

and a class diagnosis creating the structure by adding the surgery class to the constructor.

diagnosis.cs

class Diagnosis
    {
        [XmlElement("surgery")]
        public Surgery surgery
        {
            get;
            set;
        }

        public Diagnosis(Surgery Surgery)
        {
            surgery = Surgery;
        }
    }

I need to be able to serialize the class name of the surgery dynamically by adding a number before serialization happens.

does anybody know a way to achieve that?

any help is really appreciated :)

Kind regards Sandro

-- EDIT

I create the whole structure starting from my root class "Import". this class then will be passed to the serializer. So I cannot use XMLWriter in the middle of creation of the structure. I Need to create the whole structure first and finally it will be serialized:

private static void XmlFileSerialization(Import import)
{
  string filename = @"c:\dump\trauma.xml";

  // default file serialization
  XmlSerializer<Import>.SerializeToFile(import, filename);

  XmlSerializerNamespaces namespaces = new XmlSerializerNamespaces();
  namespaces.Add("", "");

  XmlWriterSettings settings = new XmlWriterSettings();
  settings.Encoding = Encoding.UTF8;
  settings.Indent = true;
  settings.IndentChars = "\t";

  XmlSerializer<Import>.SerializeToFile(import, filename, namespaces, settings);
}

and then in the Method "SerializeToFile"

public static void SerializeToFile(T source, string filename, XmlSerializerNamespaces namespaces, XmlWriterSettings settings)
        {
           if (source == null)
             throw new ArgumentNullException("source", "Object to serialize cannot be null");

           XmlSerializer serializer = new XmlSerializer(source.GetType());
           using (XmlWriter xmlWriter = XmlWriter.Create(filename, settings))
           {
              System.Xml.Serialization.XmlSerializer x = new System.Xml.Serialization.XmlSerializer(typeof(T));
              x.Serialize(xmlWriter, source, namespaces);
                    }
           }
    }

What I Need is to be able to instantiate a variable number of classes based on the main class "Surgery". The class must have a variable Name, i.e.

surgery1, surgery2, surgery3, etc.

This cannot be changed because this is given by the Institution defining the XML structure.

the class must be accessible by its dynamic Name because the property in the class must be set.

so:

surgery1.Property = "blabla";

surgery2. Property = "babla";

etc.

I am even thinking about using T4 methods to create this part of code, but there must be another way to achieve dynamic class names.

I also thought of creating instances with variable names of the class by using reflection:

System.Reflection.Assembly.GetExecutingAssembly().CreateInstance(string className)

But this doesn't work actually -.-

Does anybody have a hint and could put me in the right direction?

Martin Felber
  • 121
  • 17
  • 1
    Surely your `Diagnosis` class should have a list of `Surgery` as the xml does? – Jamiec Jun 30 '16 at 09:19
  • 1
    To achieve your goal, i recommend either implementing your own deserializationlogic or clean your xml before. `` shouldnt have those numbers. Instead the number should be anttribute `` – lokusking Jun 30 '16 at 09:25
  • You could implement `IXmlSerializable` along the lines of [how to derive xml element name from an attribute value of a class using annotations?](https://stackoverflow.com/questions/28769495). Or you could use `[XmlAnyElement]` along the lines of [How to deserialize xml elements that have different names, but the same set of attributes to a typed array/collection](http://stackoverflow.com/questions/30910834). – dbc Jun 30 '16 at 10:12
  • Thanks for the replies :) @lokusking The Problem is, that this is an XML given by a Institution, I cannot Change it -.- Otherwise I would have done it already :) – Martin Felber Jun 30 '16 at 12:58
  • Your question has turned into two questions. The first is about how to dynamically create names in xml (I gave you the answer). The second is about how to dynamically create names in c# - you should ask this question separately. – Alexander Petrov Jul 04 '16 at 12:24

2 Answers2

0

I think, you could try implement methods from IXmlSerializable in object contains diagnosisList.

trejjam
  • 21
  • 4
0

Try to use custom xml writer and reader.

public class SurgeryWriter : XmlTextWriter
{
    public SurgeryWriter(string url) : base(url, Encoding.UTF8) { }

    private int counter = 1;

    public override void WriteStartElement(string prefix, string localName, string ns)
    {
        if (localName == "surgery")
        {
            base.WriteStartElement(prefix, "surgery" + counter, ns);
            counter++;
        }
        else
            base.WriteStartElement(prefix, localName, ns);
    }
}

public class SurgeryReader : XmlTextReader
{
    public SurgeryReader(string url) : base(url) { }

    public override string LocalName
    {
        get
        {
            if (base.LocalName.StartsWith("surgery"))
                return "surgery";
            return base.LocalName;
        }
    }
}

Classes:

[XmlRoot("diagnosisList")]
public class DiagnosisList
{
    [XmlArray("diagnosis")]
    [XmlArrayItem("surgery")]
    public Surgery[] Diagnosis { get; set; }
}

[XmlRoot("surgery")]
public class Surgery
{
    [XmlElement("date", DataType = "date")]
    public DateTime Date { get; set; }
    [XmlElement("description")]
    public string Description { get; set; }
    [XmlElement("ops301")]
    public string Ops301 { get; set; }
}

Use:

var xs = new XmlSerializer(typeof(DiagnosisList));
DiagnosisList diagnosisList;

using (var reader = new SurgeryReader("test.xml"))
    diagnosisList = (DiagnosisList)xs.Deserialize(reader);

using (var writer = new SurgeryWriter("test2.xml"))
    xs.Serialize(writer, diagnosisList);

Don't mix XML and C#.

You don't need dynamic names in the C# code!

If you need an arbitrary number of instances of a class, create them in a loop and place it in any collection.

var surgeries = new List<Surgery>();

for (int i = 0; i < 10; i++)
{
    var surgery = new Surgery();
    surgeries.Add(surgery);
}

Later you can access them by index or by enumerating.

surgeries[5]

foreach (var surgery in surgeries)
{
    // use surgery
}

As you can see no need dynamic names!


Alternatively, use the dictionary with arbitrary names as keys.

var surgeryDict = new Dictionary<string, Surgery>();

for (int i = 0; i < 10; i++)
{
    var surgery = new Surgery();
    surgeryDict["surgery" + i] = surgery;
}

Access by name:

surgeryDict["surgery5"]
Alexander Petrov
  • 13,457
  • 2
  • 20
  • 49
  • thank you all for your hints, but unfortunately it did'nt work until now. as additional info: I have this structure given by a Schema, I have to serialize an not deserialize it :) – Martin Felber Jul 01 '16 at 12:51
  • @SandroColletti - My bad. Generally it would be best to do as lokusking suggests with `id` attribute. I'll see what I can do in your case. – Alexander Petrov Jul 01 '16 at 13:21
  • @SandroColletti - see update. I added custom xml writer. – Alexander Petrov Jul 01 '16 at 17:57
  • Thank you very much for your reply :) As stated before I have no Chance to Change the XML since it is given as fix structure coming from an Institution where we heva to Export our data for. I will have a look at your example :) – Martin Felber Jul 04 '16 at 07:23
  • I'm a little lost, so here some more Details. I am creating the whole structure starting in my root class "Import" which will beb passed to the serializer methods. See my UPDATE made in my question. – Martin Felber Jul 04 '16 at 12:11