Ignore class name in XML serialization

Asked

Viewed 239 times

5

I need to serialize a class for 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 for the address properties not to be inside the tag Endereco and yes directly on the tag Pessoa, in that way:

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

I didn’t want to put the class properties Endereco directly in the class Pessoa, is it possible somehow to do this?

  • You are returning your class from a Webapi?

  • ViewModel would be the option!

  • @joaoeduardorf, I don’t understand the reason for your conversation. I have some class and I will serialize it using the class Xmlserializer of C#, I believe that the way I obtain the data for it is not relevant. Please clarify?

  • 1

    @Virgilionovic, relamente Viewmodel is an option, but if it is possible otherwise would be the ideal. =/

  • Sure @Pedrocamarajunior, I’ll put an example as an answer.

4 answers

3


You can control exactly what the serialization of your class to XML will look like with the interface IXmlSerializable. If you make your class Pessoa implement this interface, you can, in the method WriteXml, choose exactly the form it will be issued when it is serialized into XML. The code below shows an example of implementation 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())));
    }
}
  • I think this is the same way, implement the interface and change the behavior as I need. I just needed to make some changes to the load load to get something more Generic, because the classes I’m using are extensive. If you don’t mind, I can edit your reply with my final solution. Thank you for the reply.

2

Directly with Xmlserializer, you won’t 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;
  • It is also a solution Julio, a little verbose but it solves the problem. But I think that between your example and using a Viewmodel, would be with Viewmodel. Anyway, great answer. + 1

1

If you can use the 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");

Exit:

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

References:

  • Virgilio, in this way I will create an XML practically in the "arm", already created the classes to avoid this type of work. The class I am using is quite extensive, I just quoted some example to get didactic. Thank you for the answer anyway. :)

  • 1

    @Pedrocamarajunior I gave you the key tip that was to create a Viewmodel in this context, you still wanted novelty and other answers, I believe that all contribute to a particular case, including your ... It was my way of helping ...! Thank you.

0

Peter, this is the example I spoke of:

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; }
}
}
  • John, what you are doing in practice is a Webservice, which by default will return a JSON from the class. What I need is the XML string itself, I am generating a file from that string. Anyway, thanks for the reply.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.