how to generate an xml in memory

3

With the code below, I generate a file and write it somewhere, however, instead of writing to disk, I wanted to generate it in memory, how do I do that?

 using (var context = new ClassContexto(ClassMaster.conexao()))
            {
                using (DbContextTransaction tran = context.Database.BeginTransaction(IsolationLevel.ReadCommitted))
                {
                    try
                    {
                        #region MyRegion
                        retorno = (from a in context.Inventario
                                   join c in context.Medicamento on a.t0051_id_medicamento equals c.t0051_id_medicamento
                                   where a.t0020_id_empresa == 1
                                   select new
                                   {
                                       c.t0051_tipo_subs,
                                       c.t0051_ms,
                                       a.t0061_lote,
                                       a.t0061_qtde,
                                       a.t0061_dt_lcto
                                   });
                        #endregion
                        XmlTextWriter writer = new XmlTextWriter(@"c:\lixos\filmes.xml", null);

                        //inicia o documento xml
                        writer.WriteStartDocument();
                        //escreve o elmento raiz
                        writer.WriteStartElement("mensagemSNGPCInventario");
                        writer.WriteAttributeString("xmlns", "urn:sngpc-schema");

                        writer.WriteRaw("<cabecalho>"
                            + "<cnpjEmissor>12935236000107</cnpjEmissor>"
                            + "<cpfTransmissor>01472346971</cpfTransmissor>"
                            + "<data>206-01-01</data>"
                            + "</cabecalho>");

                        writer.WriteStartElement("corpo");
                        writer.WriteStartElement("medicamentos");

                        foreach (var item in retorno)
                        {
                            //writer.WriteStartElement("entradaMedicamentos");
                            writer.WriteRaw(
                          "<entradaMedicamentos>"
                         + "<medicamentoEntrada>"
                          + "<classeTerapeutica> " + item.t0051_tipo_subs + " +</classeTerapeutica>"
                          + "<registroMSMedicamento>1888888888888</registroMSMedicamento>"
                          + "<numeroLoteMedicamento>AACCBB</numeroLoteMedicamento>"
                          + "<quantidadeMedicamento>12</quantidadeMedicamento>"
                           + "<unidadeMedidaMedicamento>1</unidadeMedidaMedicamento>"
                          + "</medicamentoEntrada>"
                           + "</entradaMedicamentos>"
                          );
                        }


                        // encerra o elemento raiz
                        writer.WriteEndElement();
                        //Escreve o XML para o arquivo e fecha o objeto escritor
                        writer.Close();



                    }
    
asked by anonymous 19.01.2017 / 17:47

4 answers

4

I can give you a suggestion, do not mount the XML in your hand. You can and should define a contract like the one below.

[DataContract(Name = "mensagemSNGPCInventario", Namespace = "urn:sngpc-schema")]
public class NotaFiscal
{
    [DataMember(Name = "cabecalho", Order = 1)]
    public Cabecalho Cabecalho { get; set; } = new Cabecalho();
    [DataMember(Name = "corpo", Order = 2)]
    public Corpo Corpo { get; set; } = new Corpo();
}

[DataContract(Name = "cabecalho", Namespace = "urn:sngpc-schema")]
public class Cabecalho
{
    [DataMember(Name = "cnpjEmissor", Order = 1)]
    public string CnpjEmissor { get; set; } = "12935236000107";
    [DataMember(Name = "cpfTransmissor", Order = 2)]
    public string CpfTransmissor { get; set; } = "01472346971";
    [DataMember(Name = "data", Order = 3)]
    public DateTime Data { get; set; } = new DateTime(2006, 1, 1);
}

[DataContract(Name = "corpo", Namespace = "urn:sngpc-schema")]
public class Corpo
{
    [DataMember(Name = "medicamentos", Order = 1)]
    public Medicamentos Medicamentos { get; set; } = new Medicamentos();
}

[CollectionDataContract(Name = "medicamentos", Namespace = "urn:sngpc-schema")]
public class Medicamentos : List<MedicamentoWrapper>
{

}

[DataContract(Name = "entradaMedicamentos", Namespace = "urn:sngpc-schema")]
public class MedicamentoWrapper
{
    [DataMember(Name = "medicamentoEntrada", Order = 1)]
    public Medicamento Medicamento { get; set; } = new Medicamento();
}

[DataContract(Name = "medicamentoEntrada", Namespace = "urn:sngpc-schema")]
public class Medicamento
{
    [DataMember(Name = "classeTerapeutica", Order = 1)]
    public string ClasseTerapeutica { get; set; }
    [DataMember(Name = "registroMSMedicamento", Order = 2)]
    public string RegistroMSMedicamento { get; set; } = "1888888888888";
    [DataMember(Name = "numeroLoteMedicamento", Order = 3)]
    public string NumeroLoteMedicamento { get; set; } = "AACCBB";
    [DataMember(Name = "quantidadeMedicamento", Order = 4)]
    public int QuantidadeMedicamento { get; set; } = 12;
    [DataMember(Name = "unidadeMedidaMedicamento", Order = 5)]
    public int UnidadeMedidaMedicamento { get; set; } = 1;
}

Then you can execute the following code:

var notaFiscal = new NotaFiscal();
var medicamentos = notaFiscal.Corpo.Medicamentos;
for (var indice = 0; indice < 10; indice++)
{
    var medicamento = new MedicamentoWrapper();
    medicamento.Medicamento.ClasseTerapeutica = Guid.NewGuid().ToString();
    notaFiscal.Medicamentos.Add(medicamento);
}

var serializer = new DataContractSerializer(typeof(NotaFiscal));
var settings = new XmlWriterSettings
{
    Encoding = Encoding.GetEncoding("ISO-8859-1"),
    NewLineHandling = NewLineHandling.Entitize,
    NewLineChars = Environment.NewLine,
    Indent = true
};
using (var stream = new MemoryStream())
{
    using (var writer = XmlDictionaryWriter.Create(stream, settings))
    {
        serializer.WriteObject(writer, notaFiscal);
    }

    using (var reader = new StreamReader(stream))
    {
        stream.Position = 0;
        var xml = reader.ReadToEnd();
    }
}

This will generate the following XML.:

<?xml version="1.0" encoding="utf-16"?>
<mensagemSNGPCInventario xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="urn:sngpc-schema">
  <cabecalho>
    <cnpjEmissor>12935236000107</cnpjEmissor>
    <cpfTransmissor>01472346971</cpfTransmissor>
    <data>2006-01-01T00:00:00</data>
  </cabecalho>
  <corpo>
    <medicamentos>
      <entradaMedicamentos>
        <medicamentoEntrada>
          <classeTerapeutica>a4eea288-e54e-413c-8a3a-290ac57c21fb</classeTerapeutica>
          <registroMSMedicamento>1888888888888</registroMSMedicamento>
          <numeroLoteMedicamento>AACCBB</numeroLoteMedicamento>
          <quantidadeMedicamento>12</quantidadeMedicamento>
          <unidadeMedidaMedicamento>1</unidadeMedidaMedicamento>
        </medicamentoEntrada>
      </entradaMedicamentos>
      <entradaMedicamentos>
        <medicamentoEntrada>
          <classeTerapeutica>0550972b-de44-441e-ba22-b25be0d16e3f</classeTerapeutica>
          <registroMSMedicamento>1888888888888</registroMSMedicamento>
          <numeroLoteMedicamento>AACCBB</numeroLoteMedicamento>
          <quantidadeMedicamento>12</quantidadeMedicamento>
          <unidadeMedidaMedicamento>1</unidadeMedidaMedicamento>
        </medicamentoEntrada>
      </entradaMedicamentos>
      <entradaMedicamentos>
        <medicamentoEntrada>
          <classeTerapeutica>183c17ec-2605-40fa-afc9-67bb1437e19d</classeTerapeutica>
          <registroMSMedicamento>1888888888888</registroMSMedicamento>
          <numeroLoteMedicamento>AACCBB</numeroLoteMedicamento>
          <quantidadeMedicamento>12</quantidadeMedicamento>
          <unidadeMedidaMedicamento>1</unidadeMedidaMedicamento>
        </medicamentoEntrada>
      </entradaMedicamentos>
      <entradaMedicamentos>
        <medicamentoEntrada>
          <classeTerapeutica>c581eab3-39ec-44b9-a1d9-24d9f11c7ac9</classeTerapeutica>
          <registroMSMedicamento>1888888888888</registroMSMedicamento>
          <numeroLoteMedicamento>AACCBB</numeroLoteMedicamento>
          <quantidadeMedicamento>12</quantidadeMedicamento>
          <unidadeMedidaMedicamento>1</unidadeMedidaMedicamento>
        </medicamentoEntrada>
      </entradaMedicamentos>
      <entradaMedicamentos>
        <medicamentoEntrada>
          <classeTerapeutica>90ee2e2b-ecae-4d0b-9637-3c1e638566df</classeTerapeutica>
          <registroMSMedicamento>1888888888888</registroMSMedicamento>
          <numeroLoteMedicamento>AACCBB</numeroLoteMedicamento>
          <quantidadeMedicamento>12</quantidadeMedicamento>
          <unidadeMedidaMedicamento>1</unidadeMedidaMedicamento>
        </medicamentoEntrada>
      </entradaMedicamentos>
      <entradaMedicamentos>
        <medicamentoEntrada>
          <classeTerapeutica>724ef7e2-4f0c-464a-9687-f108cbe68410</classeTerapeutica>
          <registroMSMedicamento>1888888888888</registroMSMedicamento>
          <numeroLoteMedicamento>AACCBB</numeroLoteMedicamento>
          <quantidadeMedicamento>12</quantidadeMedicamento>
          <unidadeMedidaMedicamento>1</unidadeMedidaMedicamento>
        </medicamentoEntrada>
      </entradaMedicamentos>
      <entradaMedicamentos>
        <medicamentoEntrada>
          <classeTerapeutica>83a6f068-b7d1-489e-a613-b8742e9161dd</classeTerapeutica>
          <registroMSMedicamento>1888888888888</registroMSMedicamento>
          <numeroLoteMedicamento>AACCBB</numeroLoteMedicamento>
          <quantidadeMedicamento>12</quantidadeMedicamento>
          <unidadeMedidaMedicamento>1</unidadeMedidaMedicamento>
        </medicamentoEntrada>
      </entradaMedicamentos>
      <entradaMedicamentos>
        <medicamentoEntrada>
          <classeTerapeutica>19501ba5-2f8d-4959-b0b8-85ea0dea666f</classeTerapeutica>
          <registroMSMedicamento>1888888888888</registroMSMedicamento>
          <numeroLoteMedicamento>AACCBB</numeroLoteMedicamento>
          <quantidadeMedicamento>12</quantidadeMedicamento>
          <unidadeMedidaMedicamento>1</unidadeMedidaMedicamento>
        </medicamentoEntrada>
      </entradaMedicamentos>
      <entradaMedicamentos>
        <medicamentoEntrada>
          <classeTerapeutica>28b1e29f-f947-4a4d-a654-d28687cbddc3</classeTerapeutica>
          <registroMSMedicamento>1888888888888</registroMSMedicamento>
          <numeroLoteMedicamento>AACCBB</numeroLoteMedicamento>
          <quantidadeMedicamento>12</quantidadeMedicamento>
          <unidadeMedidaMedicamento>1</unidadeMedidaMedicamento>
        </medicamentoEntrada>
      </entradaMedicamentos>
      <entradaMedicamentos>
        <medicamentoEntrada>
          <classeTerapeutica>110aebac-f3a1-421b-8402-dc6830bedeeb</classeTerapeutica>
          <registroMSMedicamento>1888888888888</registroMSMedicamento>
          <numeroLoteMedicamento>AACCBB</numeroLoteMedicamento>
          <quantidadeMedicamento>12</quantidadeMedicamento>
          <unidadeMedidaMedicamento>1</unidadeMedidaMedicamento>
        </medicamentoEntrada>
      </entradaMedicamentos>
    </medicamentos>
  </corpo>    
</mensagemSNGPCInventario>

If you want to write this XML to a file (as you are doing today), use File.WriteAllText

File.WriteAllText(filePath, xml);

If you just want to store the XML in memory, just modify the Writer you're using.

var binary = default(byte[]);
var serializer = new DataContractSerializer(typeof(NotaFiscal));
using (var stream = new MemoryStream())
{
    using (var writer = XmlDictionaryWriter.CreateBinaryWriter(stream))
    {
        serializer.WriteObject(writer, notaFiscal);                    
        stream.Position = 0;
        stream.Flush();
        binary = stream.ToArray();
    }
}
    
19.01.2017 / 18:41
3

Saving in string

Instead of passing a path by instantiating a XmlTextWriter , pass an instance of StringBuilder .

var strBuilder = new StringBuilder(); 
var writer = new XmlTextWriter(strBuilder , null);

The variable strBuilder will contain the generated XML.

Using MemoryStream

Another option is to save the stream in MemoryStream . Use an instance of XmlWriterSettings to force encoding .

var settings = new XmlWriterSettings();
settings.Enconding = Encoding.UTF8;

var stream = new MemoryStream();     
var writer = XmlWriter.Create(strBuilder , settings );

And to get the value of the stream in a string (note: do not forget to call Dispose in XmlWritter )

string conteudo = System.Text.Encoding.UTF8.GetString(myStream.GetBuffer());
    
19.01.2017 / 18:17
3

Writing raw XML (like you did) is a bad practice. There is no mention of the DTD, nor a coding statement, nor a definition of namespaces which, if not, generates an XML out of formatting pattern defined by W3C .

.NET has some classes to format this properly. @TobiasMesquita's answer is quite adequate , but I'll give you another answer with some more settings.

Use the same class domain that will be serialized in XML, with [DataContract] defined.

Implement the following extension:

public static class XmlDocumentExtensions
{
    public static XmlDocument ToXmlDocument(this object input, string encoding = "UTF-8", bool removeNamespaces = false, String xmlRoot = "", String xmlNamespace = "")
    {
        XmlSerializer ser;

        XmlDocument xd = null;

        // Se o XML for muito grande, use MemoryTributary. 
        // Veja mais sobre ele em https://github.com/tibel/Weakly
        // using (var memStm = new MemoryTributary())
        using (var memStm = new MemoryStream())
        {
            if (removeNamespaces)
            {
                ser = new XmlSerializer(input.GetType());
                XmlWriterSettings xws = new XmlWriterSettings();
                // xws.OmitXmlDeclaration = true;
                xws.Encoding = Encoding.UTF8;
                var xtw = XmlTextWriter.Create(memStm, xws);
                var namespaces = (XmlSerializerNamespaces)input.GetType().GetProperty("Namespaces").GetValue(input, null);
                ser.Serialize(xtw, input, namespaces);
            }
            else
            {
                ser = new XmlSerializer(input.GetType());
                ser.Serialize(memStm, input);
            }

            memStm.Position = 0;

            // O XML aqui está em memStr.
            // Abaixo coloco um código que demonstra como esse Stream pode ser lido
            // e devolvido na forma de um XmlDocument, por exemplo.
            // Este XmlDocument pode ser salvo em arquivo (usando FileStream)
            // ou devolvido numa aplicação Web usando return XmlContent.

            XmlReaderSettings settings = new XmlReaderSettings { CheckCharacters = false };
            settings.IgnoreWhitespace = true;
            // Se ficar muito lento, habilite a linha abaixo. 
            // Não é recomendável no início. Apenas use se seu XML está 100%.
            //settings.DtdProcessing = DtdProcessing.Prohibit;

            using (var xtr = XmlReader.Create(memStm, settings))
            {
                xd = new XmlDocument();
                xd.XmlResolver = null;
                xd.Load(xtr);
            }

            if (xd.FirstChild.NodeType == XmlNodeType.XmlDeclaration)
            {
                XmlDeclaration xmlDeclaration = (XmlDeclaration)xd.FirstChild;
                xmlDeclaration.Encoding = encoding;
            }

            return xd;
        }
    }
}

Usage:

var notaFiscal = new NotaFiscal();
// Defina todas as informações de NotaFiscal aqui.
var xmlDocument = notaFiscal.ToXmlDocument();
    
19.01.2017 / 19:20
0

Use StringBuilder at the path's path, I use this method and it works perfectly:

 StringBuilder xmlFormado = new StringBuilder();

            //Estacia o Objeto XML
            XmlWriter arqXml = XmlWriter.Create(xmlFormado, null);

             //SEU XML AQUI EX:
             arqXml.WriteStartDocument(); //Inicio do XMl
             arqXml.WriteEndDocument(); //Fim do arquivo XMl

             //libera o XmlWriter
            arqXml.Flush();
            //fechar o XmlWriter
            arqXml.Close();
            //Termina aqui

          //Os replace troca o utf-16 para 8 e limpa uma sujeira que fica no final do arquivo.
          var xmlString = xmlFormado.ToString().Replace("<?xml version=\"1.0\" encoding=\"utf-16\"?>", "").Replace(@"\", "");
    
19.01.2017 / 18:49