Ignore class name in XML serialization

5

I need to serialize a class to XML, for example:

public class Pessoa
{
    public string nome { get; set; }
    public int idade { get; set; }
    public Endereco endereco { get; set; }
}

public class Endereco
{
    public string logradouro { get; set; }
    public string numero { get; set; }
}

Serializing this class I would have the following XML:

<?xml version="1.0" encoding="UTF-8"?>
<Pessoa>
  <idade>66</idade>
  <Endereco>
     <logradouro>Rua 1</logradouro>
     <numero>123</numero>
  </endereco>
  <nome>João</nome>
</Pessoa>

What I would need is that the address properties do not fall within the Endereco tag, but directly into the Pessoa tag, like this:

<?xml version="1.0" encoding="UTF-8"?>
<Pessoa>
  <idade>66</idade>
  <logradouro>Rua 1</logradouro>
  <nome>João</nome>
  <numero>123</numero>
</Pessoa>

I did not want to put the properties of the Endereco class directly in the Pessoa class, is it possible to do this anyway?

    
asked by anonymous 02.06.2017 / 17:43

4 answers

3

You can control exactly how your class will serialize to XML with the IXmlSerializable . If you make your Pessoa class implement this interface, you can, in the WriteXml method, choose exactly what form it will emit when it is serialized to XML. The code below shows an implementation example for your scenario.

public class PtStackOverflow_209719
{
    public class Pessoa : IXmlSerializable
    {
        public string nome { get; set; }
        public int idade { get; set; }
        public Endereco endereco { get; set; }

        public override string ToString()
        {
            return string.Format("Pessoa[nome={0},idade={1},endereco={2}]",
                this.nome, this.idade, this.endereco);
        }

        public XmlSchema GetSchema()
        {
            return null;
        }

        public void ReadXml(XmlReader reader)
        {
            reader.ReadStartElement("Pessoa");
            this.nome = reader.ReadElementContentAsString();
            this.idade = reader.ReadElementContentAsInt();
            this.endereco = new Endereco();
            this.endereco.logradouro = reader.ReadElementContentAsString();
            this.endereco.numero = reader.ReadElementContentAsString();
            reader.ReadEndElement();
        }

        public void WriteXml(XmlWriter writer)
        {
            writer.WriteElementString("nome", this.nome);
            writer.WriteElementString("idade", this.idade.ToString());
            writer.WriteElementString("logradouro", this.endereco.logradouro);
            writer.WriteElementString("numero", this.endereco.numero);
        }
    }
    public class Endereco
    {
        public string logradouro { get; set; }
        public string numero { get; set; }

        public override string ToString()
        {
            return string.Format("Endereco[logradouro={0},numero={1}]",
                this.logradouro, this.numero);
        }
    }
    public static void Test()
    {
        MemoryStream ms = new MemoryStream();
        XmlSerializer xs = new XmlSerializer(typeof(Pessoa));
        Pessoa p = new Pessoa
        {
            nome = "Fulano de Tal",
            idade = 33,
            endereco = new Endereco
            {
                logradouro = "Avenida Brasil",
                numero = "123"
            }
        };
        xs.Serialize(ms, p);
        Console.WriteLine(Encoding.UTF8.GetString(ms.ToArray()));
        ms.Position = 0;
        Pessoa p2 = xs.Deserialize(ms) as Pessoa;
        Console.WriteLine(p);

        Console.WriteLine();

        ms = new MemoryStream();
        XmlSerializer xs2 = new XmlSerializer(typeof(Pessoa[]));
        xs2.Serialize(ms, new Pessoa[] { p, p2 });
        Console.WriteLine(Encoding.UTF8.GetString(ms.ToArray()));
        ms.Position = 0;
        Pessoa[] ap = xs2.Deserialize(ms) as Pessoa[];
        Console.WriteLine(string.Join(" - ", ap.Select(pp => pp.ToString())));
    }
}
    
02.06.2017 / 22:25
2

Directly with XmlSerializer, you will not be able to. An alternative is to treat XML with XmlDocument methods after serializing with XmlSerializer.

        //Instancia as classes
        Endereco e = new Endereco();
        e.logradouro = "Avenida Brasil";
        e.numero = "100";

        Pessoa p = new Pessoa();
        p.nome = "Julio";
        p.idade = 38;
        p.endereco = e;

        //Inicia XmlSerializer
        XmlSerializer xmlSerializer = new XmlSerializer(typeof(Pessoa));

        String XMLInicial;

        using (StringWriter textWriter = new StringWriter())
        {
            xmlSerializer.Serialize(textWriter, p);
            XMLInicial = textWriter.ToString();
        }

        //Carrega String no XML
        XmlDocument xml = new XmlDocument();
        xml.LoadXml(XMLInicial);

        //Obtem os ChildNodes de Endereco
        XmlNodeList NodesEndereco = xml.DocumentElement.SelectSingleNode("/Pessoa/endereco").ChildNodes;

        //Appenda Os nodes clonados para o XML dentro do NodeRoot
        for (int i = 0; i < NodesEndereco.Count; i++)
        {
            XmlNode nxn = NodesEndereco[i].Clone();
            xml.DocumentElement.AppendChild(nxn);
        }

        //Remove o node do Endereco e seus filhos
        XmlNode xn = xml.DocumentElement.SelectSingleNode("/Pessoa/endereco");
        xml.DocumentElement.RemoveChild(xn);

        //String com o resultado final
        String XMLFinal = xml.DocumentElement.OuterXml;
    
02.06.2017 / 21:43
1

If you can use class XmlDocument as follows:

Pessoa p = new Pessoa();
p.nome = "Nome 1";
p.idade = 15;
p.endereco = new Endereco { logradouro = "Rua 1", numero = "15" };

XmlDocument doc = new XmlDocument();
XmlNode docNode = doc.CreateXmlDeclaration("1.0", "UTF-8", null);
doc.AppendChild(docNode);

XmlElement root = doc.CreateElement("Pessoas");
doc.AppendChild(root);

XmlNode nome = doc.CreateNode("element", "Nome", null);
nome.InnerText = p.nome;
root.AppendChild(nome);

XmlNode idade = doc.CreateNode("element", "Idade", null);
idade.InnerText = p.idade.ToString();
root.AppendChild(idade);

XmlNode logradouro = doc.CreateNode("element", "Logradouro", null);
logradouro.InnerText = p.endereco.logradouro;
root.AppendChild(logradouro);

XmlNode numero = doc.CreateNode("element", "Numero", null);
numero.InnerText = p.endereco.numero;
root.AppendChild(numero);

doc.Save("./pessoa.xml");

Output:

<?xml version="1.0" encoding="UTF-8"?>
<Pessoas>
  <Nome>Nome 1</Nome>
  <Idade>15</Idade>
  <Logradouro>Rua 1</Logradouro>
  <Numero>15</Numero>
</Pessoas>

02.06.2017 / 23:10
0

Peter, this is the example I said:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;

namespace TesteComWebApi.Controllers
{
[Route("api/[controller]")]
public class ValuesController : Controller
{
    // GET api/values
    [HttpGet]
    public IEnumerable<string> Get()
    {
        return new string[] { "value1", "value2" };
    }

    // GET api/values/5
    [HttpGet("{id}")]
    public object Get(int id)
    {
        var pessoa = new Pessoa();
        var endereco = new Endereco();

        pessoa.nome = "Pedro Camara Junior";
        pessoa.idade = 30;
        endereco.logradouro = "Rua José da Silva";
        endereco.numero = "123";
        pessoa.endereco = endereco;

        return Ok(new{pessoa.nome, pessoa.idade, pessoa.endereco.logradouro, pessoa.endereco.numero});
    }

    // POST api/values
    [HttpPost]
    public void Post([FromBody]string value)
    {
    }

    // PUT api/values/5
    [HttpPut("{id}")]
    public void Put(int id, [FromBody]string value)
    {
    }

    // DELETE api/values/5
    [HttpDelete("{id}")]
    public void Delete(int id)
    {
    }
}

public class Pessoa
{
    public string nome { get; set; }
    public int idade { get; set; }
    public Endereco endereco { get; set; }
}

public class Endereco
{
    public string logradouro { get; set; }
    public string numero { get; set; }
}
}
    
03.06.2017 / 01:49