How would a real developer do this?

85 Views Asked by At

I am a student trying to learn how to code. I have been assigned the task of loading data from a complex XML file into a list. I've thought about how to approach this for quite a while, and this is the best I came up with. However, it feels wrong. What am I missing? How would a real developer handle this?

private void loadFromFile(string filename)//load all data from file to list
{
    try
    {
        XDocument doc = XDocument.Load(filename);

        XElement sessioniGiornaliere = doc.Root.Element("SessioniGiornaliere");

        if (sessioniGiornaliere != null)
        {

            foreach (XElement sessioneGiornaliera in sessioniGiornaliere.Elements("SessioneGiornaliera"))//sessione giornaliera is closed anytime there is there is a closingSession
            {
                List<CommercialDocument> documentList = new List<CommercialDocument>();//list of documents (containing type, es:"Vendita" ant totImport amount)
               
                foreach (XElement type in sessioneGiornaliera.Elements("DocumentiEmessi").Elements("DocumentoCommerciale"))//scrolling trough every 
                {
                    List<Line> lineList = new List<Line>();
                    List<SubLine> subLines = new List<SubLine>();                         //document before arriving at the Closure
                    string documentType = type.Elements().FirstOrDefault()?.Name.LocalName;
                    double amount = Convert.ToDouble(type.Element(documentType).Element("ImportoTotale")?.Value) / 100;
                    int numDocument = Convert.ToInt32(type.Element(documentType).Element("NumeroDocumento")?.Value);
                    foreach (XElement l in type.Elements("Vendita").Elements("Dettaglio").Elements("RigaGenerica"))//loading every doughter of riga generica
                    {
                        if(l.Element("Riga")!=null)//if the doughter is riga it loads everithing in the LineList 
                        {
                            double equivalent = Convert.ToDouble(l.Element("Riga").Element("Elemento").Element("Importo")?.Value);
                            string description = l.Element("Riga").Element("Elemento").Element("Descrizione")?.Value;
                            int qt = Convert.ToInt32(l.Element("Riga").Element("Elemento").Element("Quantita")?.Value);
                            double unitPrice = Convert.ToDouble(l.Element("Riga").Element("Elemento").Element("PrezzoUnitario")?.Value);
                            double iva = 0;//set to 0 in case instead of IVA we have Natura (wich is the same as 0)
                            if(l.Element("Riga").Element("Elemento").Element("IVA")!=null)
                                iva = Convert.ToDouble(l.Element("Riga").Element("Elemento").Element("IVA").Element("AliquotaIVA")?.Value);
                            if (l.Element("Riga").Element("ModificatoreElemento")!=null)//if it has a modifier it aplies it before loading to the list
                            {
                                if (l.Element("Riga").Element("ModificatoreElemento").Element("Segno")?.Value == "-")
                                    equivalent -= Convert.ToDouble(l.Element("Riga").Element("ModificatoreElemento").Element("Importo")?.Value);
                                else
                                    equivalent += Convert.ToDouble(l.Element("Riga").Element("ModificatoreElemento").Element("Importo")?.Value);
                            }
                            Line line = new Line(equivalent/100,description, qt,unitPrice/100, iva / 100);//divifing by 100 because Convert.TODouble doesen't work somehow
                            lineList.Add(line);
                        }else if(l.Element("RigaSubtotale")!=null)//if it is Riga subTot it loads to a different list of the document because it has different preperties
                        {
                            double subTot = Convert.ToDouble(l.Element("RigaSubtotale").Element("SubTotale")?.Value);//cheks twice because it might have a subTot and not everything else
                            if (l.Element("RigaSubtotale").Element("ModificatoreSubTotale") != null)
                            {

                                double Import = Convert.ToDouble(l.Element("RigaSubtotale").Element("ModificatoreSubTotale").Element("Importi")?.Value);
                                string sign = Convert.ToString(l.Element("RigaSubtotale").Element("ModificatoreSubTotale").Element("Segno")?.Value);
                                string description = Convert.ToString(l.Element("RigaSubtotale").Element("ModificatoreSubTotale").Element("Descrizione")?.Value);
                                SubLine subLine = new SubLine(subTot/100, Import/100, sign, description);
                                subLines.Add(subLine);
                            }
                        }
                    }
                    CommercialDocument sellingDocument = new CommercialDocument(documentType, amount,lineList,subLines,numDocument);
                    documentList.Add(sellingDocument);//adding all to the documentList
                }
                foreach (XElement closingSession in sessioneGiornaliera.Elements("ChiusuraSessione"))//list of closing sessions 
                {
                    int number = Convert.ToInt32(closingSession.Element("Numero")?.Value);
                    double equivalent = Convert.ToDouble(closingSession.Element("Corrispettivo")?.Value);
                    double totCancel = Convert.ToDouble(closingSession.Element("TotaleAnnullo")?.Value);
                    double totRefound = Convert.ToDouble(closingSession.Element("TotaleReso")?.Value);
                    string date = closingSession.Element("DataOra")?.Value;
                    string TX_dir = sessioneGiornaliera.Element("TrasmissioneCorrispettivi").Element("DatiCorrispettivi").Element("NomeFile")?.Value;
                    TX_dir = filename[0] + ":" + TX_dir;                                     //gets the directory to wich the more specific XML files are stored
                    ClosingSession a = new ClosingSession(date, equivalent / 100, totCancel / 100, totRefound / 100, documentList, TX_dir, number);
                    closingSessionList.Add(a);
                }
                
                Itemcounter++;
            }

        }
        else
            MessageBox.Show("file type incompatible");
        
        
    }catch // all the exeptions are already managed and showed in the Valida function
    {
    }
}```

    This XML file does not appear to have any style information associated with it. The document tree is shown below.




    <x:MemoriaDettaglio xmlns:x="http://ivaservizi.agenziaentrate.gov.it/docs/xsd/memoriadettaglio/export/v2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://ivaservizi.agenziaentrate.gov.it/docs/xsd/memoriadettaglio/export/v2.0 Memoria_DettaglioV3.13.xsd" versione="3.0">
        <Periodo integrale="false">
            <Dal>2024-01-03T00:00:00</Dal>
            <Al>2024-01-03T23:59:59</Al>
            <MatricolaRT>STITE500777</MatricolaRT>
            <LetturaDel>2024-01-03T14:59:05</LetturaDel>
            <Parte>1</Parte>
            <ChiaveConcatenazione>T/fk4maGA5vTmgFz31cGMFDwumG4OHF7ERS1cuUyqBg=</ChiaveConcatenazione>
            <seTerminale>1</seTerminale>
        </Periodo>
        <RecordIdentificativoDGFE>
            <DataOra>2024-01-01T16:45:12</DataOra>
            <NumeroIdentificativo>1</NumeroIdentificativo>
            <Misuratore>
                <Matricola>STITE500777</Matricola>
            </Misuratore>
        </RecordIdentificativoDGFE>
        <RecordCensimenti/>
        <RecordAttivazioni/>
        <RecordIntestazioni/>
        <SessioniGiornaliere>
            <SessioneGiornaliera>
                <DataOra>2024-01-03T14:30:08</DataOra>
                <PuntoVendita>
                    <PartitaIva>02498250345</PartitaIva>
                </PuntoVendita>
                <Modalita>RT</Modalita>
                <DocumentiEmessi>
                    <DocumentoCommerciale>
                        <Vendita>
                            <DataOra>2024-01-03T14:30:08</DataOra>
                            <NumeroDocumento>0001</NumeroDocumento>
                            <NumeroAzzeramento>0008</NumeroAzzeramento>
                            <Dettaglio>
                                <RigaGenerica>
                                    <Riga>
                                        <Elemento>
                                            <Importo>6.00</Importo>
                                            <Descrizione>REPARTO 01</Descrizione>
                                            <Quantita>1</Quantita>
                                            <PrezzoUnitario>6.00</PrezzoUnitario>
                                            <IVA>
                                                <AliquotaIVA>22.00</AliquotaIVA>
                                            </IVA>
                                        </Elemento>
                                    </Riga>
                                </RigaGenerica>
                                <RigaGenerica>
                                    <Riga>
                                        <Elemento>
                                            <Importo>5.00</Importo>
                                            <Descrizione>REPARTO 02</Descrizione>
                                            <Quantita>1</Quantita>
                                            <PrezzoUnitario>5.00</PrezzoUnitario>
                                            <IVA>
                                                <AliquotaIVA>10.00</AliquotaIVA>
                                            </IVA>
                                        </Elemento>
                                    </Riga>
                                </RigaGenerica>
                                <RigaGenerica>
                                    <Riga>
                                        <Elemento>
                                            <Importo>1.00</Importo>
                                            <Descrizione>REPARTO 01</Descrizione>
                                            <Quantita>1</Quantita>
                                            <PrezzoUnitario>1.00</PrezzoUnitario>
                                            <IVA>
                                                <AliquotaIVA>22.00</AliquotaIVA>
                                            </IVA>
                                        </Elemento>
                                        <ModificatoreElemento>
                                            <Importo>0.02</Importo>
                                            <Segno>-</Segno>
                                            <Descrizione>SCONTO</Descrizione>
                                            <IVA>
                                                <AliquotaIVA>22.00</AliquotaIVA>
                                            </IVA>
                                        </ModificatoreElemento>
                                    </Riga>
                                </RigaGenerica>
                                <RigaGenerica>
                                    <RigaSubtotale>
                                        <SubTotale>11.98</SubTotale>
                                    </RigaSubtotale>
                                </RigaGenerica>
                            </Dettaglio>
                            <ImportoTotale>11.98</ImportoTotale>
                            <Pagamenti>
                                <Pagamento>
                                    <Importo>11.98</Importo>
                                    <Tipo>PC</Tipo>
                                </Pagamento>
                            </Pagamenti>
                        </Vendita>
                    </DocumentoCommerciale>
                </DocumentiEmessi>
                <ChiusuraSessione>
                    <DataOra>2024-01-03T14:32:42</DataOra>
                    <Numero>8</Numero>
                    <Modalita>RT</Modalita>
                    <GranTotale>128.53</GranTotale>
                    <Corrispettivo>11.98</Corrispettivo>
                    <TotaleAnnullo>0.00</TotaleAnnullo>
                    <TotaleReso>0.00</TotaleReso>
                    <NumeroDocumentiCommerciali>1</NumeroDocumentiCommerciali>
                </ChiusuraSessione>
                <TrasmissioneCorrispettivi>
                    <DatiCorrispettivi>
                        <DataOra>2024-01-03T14:32:52</DataOra>
                        <NomeFile>\XML\SENT\CORR\OK\Z0001_Z0025\202401031432_Z0008.xml</NomeFile>
                        <RispostaNomeFile>\XML\SENT\CORR\OK\Z0001_Z0025\R_202401031432_Z0008.xml</RispostaNomeFile>
                        <Rif_Trasmissione_Telematica>155914705</Rif_Trasmissione_Telematica>
                        <StatoInvio>INVIATO</StatoInvio>
                    </DatiCorrispettivi>
                </TrasmissioneCorrispettivi>
            </SessioneGiornaliera>
            <SessioneGiornaliera>
                <DataOra>2024-01-03T14:52:20</DataOra>
                <PuntoVendita>
                    <PartitaIva>02498250345</PartitaIva>
                </PuntoVendita>
                <Modalita>RT</Modalita>
                <DocumentiEmessi>
                    <DocumentoCommerciale>
                        <Vendita>
                            <DataOra>2024-01-03T14:52:20</DataOra>
                            <NumeroDocumento>0001</NumeroDocumento>
                            <NumeroAzzeramento>0009</NumeroAzzeramento>
                            <Dettaglio>
                                <RigaGenerica>
                                    <Riga>
                                        <Elemento>
                                            <Importo>4.00</Importo>
                                            <Descrizione>REPARTO 01</Descrizione>
                                            <Quantita>1</Quantita>
                                            <PrezzoUnitario>5.00</PrezzoUnitario>
                                            <IVA>
                                                <AliquotaIVA>22.00</AliquotaIVA>
                                            </IVA>
                                        </Elemento>
                                    </Riga>
                                </RigaGenerica>
                                <RigaGenerica>
                                    <Riga>
                                        <Elemento>
                                            <Importo>6.00</Importo>
                                            <Descrizione>REPARTO 02</Descrizione>
                                            <Quantita>1</Quantita>
                                            <PrezzoUnitario>6.00</PrezzoUnitario>
                                            <IVA>
                                                <AliquotaIVA>10.00</AliquotaIVA>
                                            </IVA>
                                        </Elemento>
                                    </Riga>
                                </RigaGenerica>
                                <RigaGenerica>
                                    <Riga>
                                        <Elemento>
                                            <Importo>5.00</Importo>
                                            <Descrizione>REPARTO 01</Descrizione>
                                            <Quantita>1</Quantita>
                                            <PrezzoUnitario>5.00</PrezzoUnitario>
                                            <IVA>
                                                <AliquotaIVA>22.00</AliquotaIVA>
                                            </IVA>
                                        </Elemento>
                                    </Riga>
                                </RigaGenerica>
                                <RigaGenerica>
                                    <Riga>
                                        <Elemento>
                                            <Importo>9.00</Importo>
                                            <Descrizione>REPARTO 01</Descrizione>
                                            <Quantita>1</Quantita>
                                            <PrezzoUnitario>9.00</PrezzoUnitario>
                                            <IVA>
                                                <AliquotaIVA>22.00</AliquotaIVA>
                                            </IVA>
                                        </Elemento>
                                    </Riga>
                                </RigaGenerica>
                                <RigaGenerica>
                                    <Riga>
                                        <Elemento>
                                            <Importo>1.00</Importo>
                                            <Descrizione>REPARTO 02</Descrizione>
                                            <Quantita>1</Quantita>
                                            <PrezzoUnitario>1.00</PrezzoUnitario>
                                            <IVA>
                                                <AliquotaIVA>10.00</AliquotaIVA>
                                            </IVA>
                                        </Elemento>
                                    </Riga>
                                </RigaGenerica>
                                <RigaGenerica>
                                    <Riga>
                                        <Elemento>
                                            <Importo>9.00</Importo>
                                            <Descrizione>REPARTO 03</Descrizione>
                                            <Quantita>1</Quantita>
                                            <PrezzoUnitario>9.00</PrezzoUnitario>
                                            <IVA>
                                                <AliquotaIVA>4.00</AliquotaIVA>
                                            </IVA>
                                        </Elemento>
                                        <ModificatoreElemento>
                                            <Importo>0.54</Importo>
                                            <Segno>-</Segno>
                                            <Descrizione>SCONTO</Descrizione>
                                            <IVA>
                                                <AliquotaIVA>4.00</AliquotaIVA>
                                            </IVA>
                                        </ModificatoreElemento>
                                    </Riga>
                                </RigaGenerica>
                                <RigaGenerica>
                                    <Riga>
                                        <Elemento>
                                            <Importo>2.00</Importo>
                                            <Descrizione>REPARTO 03</Descrizione>
                                            <Quantita>1</Quantita>
                                            <PrezzoUnitario>2.00</PrezzoUnitario>
                                            <IVA>
                                                <AliquotaIVA>4.00</AliquotaIVA>
                                            </IVA>
                                        </Elemento>
                                        <ModificatoreElemento>
                                            <Importo>0.04</Importo>
                                            <Segno>-</Segno>
                                            <Descrizione>SCONTO</Descrizione>
                                            <IVA>
                                                <AliquotaIVA>4.00</AliquotaIVA>
                                            </IVA>
                                        </ModificatoreElemento>
                                    </Riga>
                                </RigaGenerica>
                            </Dettaglio>
                            <ImportoTotale>36.42</ImportoTotale>
                            <Pagamenti>
                                <Pagamento>
                                    <Importo>36.42</Importo>
                                    <Tipo>PC</Tipo>
                                </Pagamento>
                            </Pagamenti>
                        </Vendita>
                    </DocumentoCommerciale>
                </DocumentiEmessi>
                <ChiusuraSessione>
                    <DataOra>2024-01-03T14:54:43</DataOra>
                    <Numero>9</Numero>
                    <Modalita>RT</Modalita>
                    <GranTotale>164.95</GranTotale>
                    <Corrispettivo>36.42</Corrispettivo>
                    <TotaleAnnullo>0.00</TotaleAnnullo>
                    <TotaleReso>0.00</TotaleReso>
                    <NumeroDocumentiCommerciali>1</NumeroDocumentiCommerciali>
                </ChiusuraSessione>
                <TrasmissioneCorrispettivi>
                    <DatiCorrispettivi>
                        <DataOra>2024-01-03T14:54:52</DataOra>
                        <NomeFile>\XML\SENT\CORR\OK\Z0001_Z0025\202401031454_Z0009.xml</NomeFile>
                        <RispostaNomeFile>\XML\SENT\CORR\OK\Z0001_Z0025\R_202401031454_Z0009.xml</RispostaNomeFile>
                        <Rif_Trasmissione_Telematica>155914737</Rif_Trasmissione_Telematica>
                        <StatoInvio>INVIATO</StatoInvio>
                    </DatiCorrispettivi>
                </TrasmissioneCorrispettivi>
            </SessioneGiornaliera>
        </SessioniGiornaliere>
    </x:MemoriaDettaglio>



2

There are 2 best solutions below

6
Marc Gravell On

Everything in "real"† programming is contextual.

If the shape of the data is fixed, and the data size is reasonable, then you would typically use a serialization library; in the case of C# XmlSerializer is probably ideal, and there are tools to automatically generate starter code from either a schema file or an example xml file.

If the shape of the data is dynamic, you'd have to use a DOM API (XDocument / XmlDocument), and/or something like xslt, but this is a more niche scenario.

If the data volume is huge (i.e. too large to reasonably load into memory at once as either a DOM or a deserialized object model), you'd have to use a streaming API, for example XmlReader; this is very much "hard mode", and is rarely needed.

The code in the question appears to be manually implementing deserialization based on a DOM; this is the worst of both worlds:

  • you're doing a lot of work yourself that can be trivially automated by a library
  • you're forcing things to use a DOM rather than a reader, which adds an additional copy of all the data into transient memory (it'll be collected later, assuming it isn't rooted, but: it is unnecessary overhead)

If you post an example of the XML, people here can probably show you how to get that working with XmlSerializer in minimal code.


† the quotes here are parody; I hate gatekeeping - we don't need to disambiguate "real" developers


Partial example based on the xml example in the comments below; there are a lot of configuration options for XmlSerializer, usually involving attributes - [XmlArray], [XmlElement] and [XmlAttribute] being the most common (there are others):

// expanded so I could terminate the elements correctly
var xml = """
<SessioniGiornaliere>
    <SessioneGiornaliera>
        <DataOra>2024-01-03T14:30:08</DataOra>
        <PuntoVendita>
            <PartitaIva>02498250345</PartitaIva>
        </PuntoVendita>
        <Modalita>RT</Modalita>
        <DocumentiEmessi>
            <DocumentoCommerciale>
                <Vendita>
                    <DataOra>2024-01-03T14:30:08</DataOra>
                    <NumeroDocumento>0001</NumeroDocumento>
                    <NumeroAzzeramento>0008</NumeroAzzeramento>
                    <Dettaglio>
                        <RigaGenerica>
                            <Riga>
                                <Elemento>
                                    <Importo>6.00</Importo>
                                    <Descrizione>REPARTO 01</Descrizione>
                                    <Quantita>1</Quantita>
                                    <PrezzoUnitario>6.00</PrezzoUnitario>
                                </Elemento>
                            </Riga>
                        </RigaGenerica>
                    </Dettaglio>
                </Vendita>
            </DocumentoCommerciale>
        </DocumentiEmessi>
    </SessioneGiornaliera>
</SessioniGiornaliere>
""";

with

var serializer = new XmlSerializer(typeof(SessioniGiornaliere));
var obj = (SessioniGiornaliere)serializer.Deserialize(new StringReader(xml))!;

Console.WriteLine(obj.Sessions.Count);
foreach (var session in obj.Sessions)
{
    Console.WriteLine(session.DataOra);
    Console.WriteLine(session.PuntoVendita.PartitaIva);
    Console.WriteLine(session.Modalita);
}

public class SessioniGiornaliere
{
    [XmlElement("SessioneGiornaliera")]
    public List<SessioneGiornaliera> Sessions { get; } = new();
}

public class SessioneGiornaliera
{
    public DateTime DataOra { get; set; }
    public PuntoVendita PuntoVendita { get; set; }
    public string Modalita { get; set; }
}
public class PuntoVendita
{
    public string PartitaIva { get; set; }
}

and using the xml in the question:

using System.Xml.Serialization;

var xml = """
<x:MemoriaDettaglio xmlns:x="http://ivaservizi.agenziaentrate.gov.it/docs/xsd/memoriadettaglio/export/v2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://ivaservizi.agenziaentrate.gov.it/docs/xsd/memoriadettaglio/export/v2.0 Memoria_DettaglioV3.13.xsd" versione="3.0">
<Periodo integrale="false">
<Dal>2024-01-03T00:00:00</Dal>
<Al>2024-01-03T23:59:59</Al>
</Periodo>
</x:MemoriaDettaglio>
""";

var ser = new XmlSerializer(typeof(MemoriaDettaglio));
var obj = (MemoriaDettaglio)ser.Deserialize(new StringReader(xml))!;
Console.WriteLine(obj.Versione);
Console.WriteLine(obj.Periodo.Integrale);
Console.WriteLine(obj.Periodo.Dal);
Console.WriteLine(obj.Periodo.Al);

[XmlRoot("MemoriaDettaglio", Namespace = "http://ivaservizi.agenziaentrate.gov.it/docs/xsd/memoriadettaglio/export/v2.0")]
public class MemoriaDettaglio
{
    [XmlAttribute("versione")]
    public string Versione { get; set; }
    [XmlElement(Namespace = "")]
    public Periodo Periodo { get; set; }
}

public class Periodo
{
    [XmlAttribute("integrale")]
    public bool Integrale { get; set; }
    public DateTime Dal { get; set; }
    public DateTime Al { get; set; }
}
3
Michael Kay On

Firstly, you say you want to load XML data into a list, but you don't say why. What is the wider objective? What are you going to do with the list once you have got it? Can you achieve the wider objective without loading the data into a list? Converting data from one form to another is only a means to an end, and we need to know what that end is. A real developer would (or should) be asking a lot of questions about the requirements rather than worrying about the code.

There's a school of thought that it's best to leave the data in XML "end to end" rather than converting it to some other form. Use XML-specific technologies like XSLT and XQuery to avoid the conversion overheads (programmer time and computation time). But you can't do something "end to end" without knowing what the ends are.

Secondly, real developers work under project constraints. There will be preferred technologies, things that the team is familiar with, things that have been approved for use. There will be budgets and policies and managers and users and technical infrastructure (not to mention deadlines and performance requirements) that all affect your freedom of action. Real developers have to adopt approaches within these constraints. What that means is that we can't answer your question, because we don't know anything about those constraints.