Extract data from an xml file in c #

1

I have an xml file from which I want to extract the concepts of an invoice

<cfdi:Conceptos>
  <cfdi:Concepto importe="13000.00" valorUnitario="13000.00" descripcion="Servicio profesional médico" unidad="No Aplica" cantidad="1" />
  <cfdi:Concepto importe="90.000" valorUnitario="90.000" descripcion="Servicio profesional médico" unidad="No Aplica" cantidad="1" />
</dfdi:Conceptos>

For this I use the following code:

List<object[]> listaConceptos = new List<object[]>();
var conceptos = from c in doc.Descendants()
                where c.Name.LocalName == "Conceptos"
                select c.Elements();

foreach (var item in conceptos)
{
    object[] dato = new object[5];
    dato[0] = item.Attributes("cantidad").First().Value;
    dato[1] = item.Attributes("unidad").First().Value;
    dato[2] = item.Attributes("descripcion").First().Value;
    dato[3] = item.Attributes("valorUnitario").First().Value;
    dato[4] = item.Attributes("importe").First().Value;

    listaConceptos.Add(dato);
}

But it only works for me if it's a single concept, because it only saves me the first concept in the arrangement and the others no longer.

    
asked by Miriam 29.08.2017 в 00:31
source

3 answers

0

The expression:

from c in doc.Descendants()
where c.Name.LocalName == "Conceptos"
select c.Elements();

Return a collection of XElement or IEnumerable<IEnumerable<XElement>> . In other words this:

 IEnumerable<IEnumerable<XElement>> conceptos = from c in doc.Descendants()
                            where c.Name.LocalName == "Conceptos"
                            select c.Elements();

Therefore you have 2 options:

You go through the collection of collections to read the data. In other words, you make a foreach and for each element you make another foreach to go through the current element of the first foreach (one foreach inside another):

List<object[]> listaConceptos = new List<object[]>();
            var conceptos = from c in doc.Descendants()
                            where c.Name.LocalName == "Conceptos"
                            select c.Elements();

            foreach (IEnumerable<XElement> item in conceptos)
            {
                foreach (var conceptoXML in item)
                {
                    object[] dato = new object[5];
                    dato[0] = conceptoXML.Attribute("cantidad").Value;
                    dato[1] = conceptoXML.Attribute("unidad").Value;
                    dato[2] = conceptoXML.Attribute("descripcion").Value;
                    dato[3] = conceptoXML.Attribute("valorUnitario").Value;
                    dato[4] = conceptoXML.Attribute("importe").Value;

                    listaConceptos.Add(dato);
                }
            }

Or you get the first result of the collection of the expression with the method FirstOrDefault() :

List<object[]> listaConceptos = new List<object[]>();
            IEnumerable<XElement> conceptos = (from c in doc.Descendants()
                            where c.Name.LocalName == "Conceptos"
                            select c.Elements())
                            .FirstOrDefault(); // retornar solo el primer resultado de la coleccion de colecciones de XElement


            foreach (XElement conceptoXML in conceptos)
            {

                    object[] dato = new object[5];
                    dato[0] = conceptoXML.Attribute("cantidad").Value;
                    dato[1] = conceptoXML.Attribute("unidad").Value;
                    dato[2] = conceptoXML.Attribute("descripcion").Value;
                    dato[3] = conceptoXML.Attribute("valorUnitario").Value;
                    dato[4] = conceptoXML.Attribute("importe").Value;

                    listaConceptos.Add(dato);

            }
    
answered by 29.08.2017 / 01:04
source
1

The answer is very simple, in your foreach you need to change:

foreach (var item in conceptos)

Because of this:

foreach (var item in conceptos.ElementAt(0))

This means that you already have the node, now you simply need to access the elements.

    
answered by 29.08.2017 в 01:16
0

Here's one way:

With the following instruction, you get all the xml elements that are concept, when you put it to the end toList you get it in a list

List<XElement> li = doc.Descendants("Concepto").ToList();

In the next instruction, you go through the list of 'concepts' and you get the attributes for each concept and assign them to your object

List<object[]> listaConceptos = new List<object[]>();
foreach(var item in li)
{
    object[] dato = new object[5];

    dato[0] = item.Attribute("cantidad").Value;
    dato[1] = item.Attribute("unidad").Value;
    dato[2] = item.Attribute("descripcion").Value;
    dato[3] = item.Attribute("valorUnitario").Value;
    dato[4] = item.Attribute("importe").Value;

    listaConceptos.Add(dato);
}
    
answered by 29.08.2017 в 01:30