Home > Blockchain >  XmlSerialisation without root in C#
XmlSerialisation without root in C#

Time:06-11

I have this object

var myObj = new Root
{
    Items = new List<Items>
    {
        new Items { MyValue1 = "test", MyValue2 = 22 },
        new Items { MyValue1 = "test2", MyValue2 = 44 },
    }
};

with

public class Root
{
    public List<Items> Items { get; set; }
}

public class Items
{
    public string MyValue1 { get; set; }
    public int MyValue2 { get; set; }
}

I can serialize it like this :

<Root>
    <Items>
        <Items>
            <MyValue1>test</MyValue1>
            <MyValue2>22</MyValue2>
        </Items>
        <Items>
            <MyValue1>test2</MyValue1>
            <MyValue2>44</MyValue2>
        </Items>
    </Items>
</Root>

But I would like to serialize like :

<Items>
    <MyValue1>test</MyValue1>
    <MyValue2>22</MyValue2>
</Items>
<Items>
    <MyValue1>test2</MyValue1>
    <MyValue2>44</MyValue2>
</Items>

But I can't find a way to do this

This is the reproduction code :

class Program
{
    static void Main(string[] args)
    {
        var myObj = new Root
        {
            Items = new List<Items>
            {
                new Items { MyValue1 = "test", MyValue2 = 22 },
                new Items { MyValue1 = "test2", MyValue2 = 44 },
            }
        };

        var serializer = new XmlSerializer(typeof(Root));
        var ms = new MemoryStream();
        var settings = new XmlWriterSettings { Encoding = new UTF8Encoding(false), OmitXmlDeclaration = true };
        using var xmlWriter = XmlWriter.Create(ms, settings);
        var ns = new XmlSerializerNamespaces();
        ns.Add(string.Empty, string.Empty);
        serializer.Serialize(xmlWriter, myObj, ns);

        var xmlDebug = Encoding.UTF8.GetString(ms.ToArray());

        var result = @"<?xml version=""1.0"" encoding=""utf-8""?><Items><MyValue1>test</MyValue1><MyValue2>22</MyValue2></Items><Items><MyValue1>test2</MyValue1><MyValue2>44</MyValue2></Items>";
        Assert.AreEqual(result, xmlDebug);

    }
}

public class Root
{
    public List<Items> Items { get; set; }
}

public class Items
{
    public string MyValue1 { get; set; }
    public int MyValue2 { get; set; }
}

CodePudding user response:

You can use xml attributes in your data models.

public class Root
{
    [XmlElement("Items")]
    public List<Items> Items { get; set; }
}

public class Items
{
    public string MyValue1 { get; set; }
    public int MyValue2 { get; set; }
}

Default xml attribute for "List" is XmlArrayItem, if you use XmlElement for it, this will be your result

<Root>
    <Items>
        <MyValue1>test</MyValue1>
        <MyValue2>22</MyValue2>
    </Items>
    <Items>
        <MyValue1>test2</MyValue1>
        <MyValue2>44</MyValue2>
    </Items>
</Root>

And xml format must have one root node always. If you want to change root node name you can use XmlRoot attribute for Root class.

[XmlRoot("AnotherName")]
public class Root
{
    [XmlElement("Items")]
    public List<Items> Items { get; set; }
}

CodePudding user response:

Let me preface with I agree with the other comments that this sounds like a bad idea! But also if you are stuck with this as you say, I think you could try something like:

string xml = myObj.Items.Aggregate(seed: new StringBuilder(),
    func: (builder, item) =>
    {
        using var writer = new StringWriter();
        new XmlSerializer(typeof(Items))
            .Serialize(writer, item);
        return builder.AppendLine(writer.ToString());
    }).ToString();

As you want some unusually structured XML, you are working against the intentions of the XmlSerializer. But we can still use it to build up valid serialized XML fragments. The solution aggreagates these valid fragments into a single string with a StringBuilder.

For simplicity I've used a StringWriter, but you can slot in your XmlWriter etc. for pretty print as you require.

  • Related