Home > front end >  How do I read data in C# from an XML file that has no index?
How do I read data in C# from an XML file that has no index?

Time:02-05

I am currently creating a time registry and need to sort, order and filter the data. My goal is to to input the raw data, so logging in and out of a building per day, and to output an XML file that contains a list of the times that each person was logged in per day.

I am familiar with Python, but am new to C# and XML. My problem is, is that all examples on XML that I have found contain a structured tree as such:

<PurchaseOrder>
    <MyAddress>
        <FirstName>George</FirstName>
    </MyAddress>
</PurchaseOrder>

I have tried to read and print data with XElement, XmlDocument, XmlNode and have succeeded to print all data without iterating through the lines. I have now made enough changes for nothing to work anymore. Could someone please point me in the right direction to which Xml classes or if I should use LINQ, DOM or XPath to sort and filter XML data.

    public void PrintData()
    {
        var fileName = "C/<user>/documents/Events.xml";

        XmlDocument doc = new XmlDocument();
        doc.Load(fileName);
        Console.WriteLine("doc", doc);

        XmlElement Data = doc.DocumentElement;

        XmlAttributeCollection attrColl = Data.Attributes;
        for (int i = 0; i < attrColl.Count; i  ) ;
        {
            Console.Write("{0} = ", attrColl[i].Name);
            Console.Write("{0}", attrColl[i].Value);
        }

        XElement el = XElement.Load(fileName);
        foreach (var item in el.Ancestors())
        {
            Console.WriteLine("Ancestors", item);
        }

        IList<XElement> indexedElements = el.Elements().ToList();
        Console.WriteLine("indexedelements", indexedElements[0]);

        IEnumerable<XElement> childElements =
            from elements in el.Elements()
            select elements;
        foreach (XElement elements in childElements)
            Console.WriteLine("name", el);

    }

raw data above and desired data below

<?xml version="1.0" encoding="utf-8"?>
<Events xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <EventList>
    <DATA datetime="2022-02-04 15:00:00" name="mr john" action="leave"/>
    <DATA datetime="2022-02-04 15:00:00" name="jane doe" action="leave"/>
    <DATA datetime="2022-02-04 14:00:00" name="jane doe" action="enter"/>
    <DATA datetime="2022-02-04 13:30:00" name="jane doe" action="leave"/>
    <DATA datetime="2022-02-04 13:00:00" name="mr john" action="enter"/>
    <DATA datetime="2022-02-04 12:00:00" name="jane doe" action="enter"/>
    <DATA datetime="2022-02-03 15:00:00" name="mr john" action="leave"/>
    <DATA datetime="2022-02-03 15:00:00" name="jane doe" action="leave"/>
    <DATA datetime="2022-02-03 13:00:00" name="mr john" action="enter"/>
    <DATA datetime="2022-02-03 12:00:00" name="jane doe" action="enter" />
  </EventList>
</Events>
<?xml version="1.0" encoding="utf-8"?>
<Events xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <EventList>
     <DATA datetime="2022-02-04" name="mr john" totaltime="2" />
     <DATA datetime="2022-02-04" name="jane doe" totaltime="2.5" />
     <DATA datetime="2022-02-03" name="mr john" totaltime="2" />
     <DATA datetime="2022-02-03" name="jane doe" totaltime="3" />
  </EventList>
</Events>

CodePudding user response:

Try following using Xml Linq

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Xml;
using System.Xml.Linq;


namespace ConsoleApplication11
{
    class Program
    {
        const string FILENAME = @"c:\temp\test.xml";
        static void Main(string[] args)
        {
            Event[] events = new Event[] {
                new Event { date = DateTime.Parse("2022-02-04 15:00:00"), name = "mr john", action = "leave"},
                new Event { date = DateTime.Parse("2022-02-04 15:00:00"), name = "jane doe", action = "leave"},
                new Event { date = DateTime.Parse("2022-02-04 14:00:00"), name = "jane doe", action = "enter"},
                new Event { date = DateTime.Parse("2022-02-04 13:30:00"), name = "jame doe", action = "leave"},
                new Event { date = DateTime.Parse("2022-02-04 13:00:00"), name = "mr john", action = "enter"},
                new Event { date = DateTime.Parse("2022-02-04 12:00:00"), name = "jane doe", action = "enter"},
                new Event { date = DateTime.Parse("2022-02-04 15:00:00"), name = "mr john", action = "leave"},
                new Event { date = DateTime.Parse("2022-02-04 15:00:00"), name = "jane doe", action = "leave"},
                new Event { date = DateTime.Parse("2022-02-04 13:00:00"), name = "mr john", action = "enter"},
                new Event { date = DateTime.Parse("2022-02-04 12:00:00"), name = "jane doe", action = "enter"}
            };

            string header = "<?xml version=\"1.0\" encoding=\"utf-8\"?>"  
                            "<Events xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\">"  
                               "<EventList>"  
                               "</EventList>"  
                            "</Events>";

            XDocument doc = XDocument.Parse(header);
            XElement eventList = doc.Descendants("EventList").First();
   
            foreach(Event evnt in events)
            {
                XElement data = new XElement("DATA", new object[] {
                    new XAttribute("datetime", evnt.date.ToString("yyyy-mm-dd HH:mm:ss")),
                    new XAttribute("name", evnt.name),
                    new XAttribute("action", evnt.action)
                });
                eventList.Add(data);
            }

            doc.Save(FILENAME);

        }
  
    }
    public class Event
    {
        public DateTime date { get; set; }
        public string name { get; set; }
        public string action { get; set; }
    }
 
}

CodePudding user response:

Your code is a little muddled. I'd stick to LINQ to XML (so XDocument, XElement, XAttribute etc.). You can read your XML into strongly-typed objects like this:

var doc = XDocument.Load(fileName);

var data =
    from e in doc.Descendants("DATA")
    select new
    {
        Date = (DateTime)e.Attribute("datetime"),
        Name = (string)e.Attribute("name"),
        Action = (string)e.Attribute("action")
    };

And you can then use this to generate your new data. I'm not entirely clear how you're mapping to this, so I've just gone with grouping by date and name and returning the count as totaltime. You can change to whatever logic you need - I'm mainly demonstrating how you'd create the XML:

var newData =
    from item in data
    group item.Action by new { item.Date.Date, item.Name }
    into g
    select new XElement("Data",
        new XAttribute("datetime", XmlConvert.ToString(g.Key.Date, "yyyy-MM-dd")),
        new XAttribute("name", g.Key.Name),
        new XAttribute("totaltime", g.Count())
    );

var newDoc = new XDocument(
    new XElement("Events",
        new XElement("EventList", newData)
    ));

newDoc.Save(newFileName);

You can see a working demo here.

  •  Tags:  
  • Related