1

My XML file looks like:

<device name="dev. 1" nodes="16" scenarios="20">
  <package>Pack. 1</package>
  <info>info...</info>
  <picture>pic</picture>
  <nodes>
    <node no="1" name="OUT_1" type="source"/>
    <node no="2" name="OUT_2" type="source"/>
    <node no="3" name="OUT_3" type="source"/>
    <node no="4" name="OUT_4" type="source"/>
  </nodes>
  <scenario name="scenario 1">
    <zth m_node="1" d_node="1" model="table" points="190">
      <data time="1" value="0.1"/>
      <data time="2" value="2"/>
      <data time="2" value="4"/>
    </zth>
    <zth m_node="1" d_node="2" model="table" points="190">
      <data time="1" value="0.3"/>
      <data time="2" value="4"/>
    </zth>
  </scenario>
  <scenario name="scenario 2">
    <zth m_node="1" d_node="1" model="table" points="190">
      <data time="2" value="2"/>
      <data time="1" value="0.3"/>
      <data time="2" value="4"/>
    </zth>
    <zth m_node="1" d_node="2" model="table" points="190">
      <data time="1" value="0.3"/>
      <data time="2" value="4"/>
    </zth>
  </scenario>
</device>

The data I need to read is: The Attribute name from the Element scen from the is in the <data>, I need to get the time and value from the data into arrays but only when the d_node="2" in the <zth>.

This is what I have tried:

    public class Scenario {
        public string name { get; set; }
        public List<string> ZthList { get; set; }
    }

    public class Zth {
        public string m_node { get; set; }
        public string d_node { get; set; }
        public string time { get; set; }
        public string value { get; set; }
    }
    public class XMLReader
    {

        public void xmlReader()
        {

            string currentDir = Environment.CurrentDirectory;
            //getting the directory
            DirectoryInfo directory = new DirectoryInfo(
            Path.GetFullPath(Path.Combine(currentDir, @"..\..\" + @"utils\XML\XMLFile1.xml")));

            XDocument doc = XDocument.Load(Path.Combine(currentDir, @"..\..\" + @"utils\XML\XMLFile1.xml"));
            var scenarios = (from s in doc.Root.Elements("scenario")
                             select new Scenario{
                                 name = (string)s.Attribute("name"), 
                                 ZthList = s.Elements("zth")
                                            .Select(r => new Zth
                                            {
                                                m_node = (string)r.Attribute("m_node"),
                                                d_node = (string)r.Attribute("d_node"),
                                                time = (string)r.Element("data").Attribute("time"),
                                                value = (string)r.Element("data").Attribute("value"),
                                            }).ToList()
                             }).ToList();
            var zth_d_node = scenarios.Where(x => x.ZthList.Any(r => r.d_node == "1")).ToList();
            var s_names = scenarios.Where(x => x.Element("").Value.Equals("name")).toList();

            Console.WriteLine("List: ");
            Console.WriteLine(String.Join(", ", scenarios));
        }
    }

I am getting and error: Severity Code Description Project File Line Suppression State Error CS0029 Cannot implicitly convert type 'System.Collections.Generic.List<project1.utils.Zth>' to 'System.Collections.Generic.List<string>'

Also the data from the time and value is of type double I changed it to string because I was getting a similar error but still it's not working

2 Answers 2

1

You need to improve your model to the structure of xml data. See:

public class Scenario {
    public string name { get; set; }
    public List<Zth> ZthList { get; set; }
}

public class Zth {
    public string m_node { get; set; }
    public string d_node { get; set; }
    public List<Data> data { get; set; }
}

public class Data {
    public string t { get; set; }
    public string v { get; set; }
}

Then:

XDocument xdoc = XDocument.Load(...);
List<Scenario> scenarios = xdoc.Descendants("scenario")
    .Select(x=> new Scenario()
        {
            name= x.Attribute("name").Value, 
            ZthList= x.Descendants("zth")
                .Select(y=> new Zth()
                {
                    m_node = y.Attribute("m_node").Value,
                    d_node = y.Attribute("d_node").Value, 
                    data = y.Descendants("data")
                        .Select(z => new Data()
                        {
                            t =  z.Attribute("time").Value,
enter code here

                            v = z.Attribute("value").Value,
                        })
                        .ToList()
                }).ToList()
        }).ToList();

EDIT

If you would like to get only those zth nodes where d_node is equal to 1, you can change this line:

...
ZthList= x.Descendants("zth")
    .Where(n=> n.Attribute("d_node").Value == "1")  //condition was added
    .Select(y=> new Zth()
...

Then result will look like:

List of scenarios

Sign up to request clarification or add additional context in comments.

5 Comments

Thanks for the hint. I was trying to create a list with all the time values but only when the d_node attribute is 1 in the zth element, how can I save this in another list?
@kristian, what if the d_node attribute is not equal to 1? data member of zth class will be null! Is it ok?
If d_node is not 1 the time and value can be ignored, it is relevant only when it's 1.
When I display the values of the t: Console.WriteLine(String.Join(", ", scenarios.Select(x => x.ZthList.Select(y => y.data.Select(z => z.t))))); I don't get the values, but I get this instead: System.Linq.Enumerable+WhereSelectListIterator 2[prj.utils.Zth,System.Collections.Generic.IEnumerable 1[System.String]], System.Linq.Enumerable+WhereSelectListIterator 2[prj.utils.Zth,System.Collections.Generic.IEnumerable 1[System.String]] . I tried to get the names of scenarios this way and it works: Console.WriteLine(String.Join(", ", scenarios.Select(x => x.name))); Did I get something wrong?
foreach(Scenario sc in scenarios) { Console.WriteLine($"---=== {sc.name} ===---"); foreach(Zth z in sc.ZthList) { Console.WriteLine("times: {0}", string.Join(";", z.data.Select(x=>x.t))); Console.WriteLine("values: {0}", string.Join(";", z.data.Select(x=>x.v))); } }
1

I made a bunch of changes. I always recommend to avoid "var" unless it is necessary. You were totally confused because you didn't know the variable types. :

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

namespace ConsoleApplication16
{
    class Program
    {
        const string FILENAME = @"c:\temp\test.xml";
        static void Main(string[] args)
        {
            XMLReader xReader = new XMLReader();
            xReader.xmlReader(FILENAME);
        }
 
    }
    public class Scenario
    {
        public string name { get; set; }
        public List<Zth> ZthList { get; set; }
    }

    public class Zth
    {
        public string m_node { get; set; }
        public string d_node { get; set; }
        public string time { get; set; }
        public string value { get; set; }
    }
    public class XMLReader
    {

        public void xmlReader(string filename)
        {


            XDocument doc = XDocument.Load(filename);
            List<Scenario> scenarios = (from s in doc.Root.Elements("scenario")
                             select new Scenario
                             {
                                 name = (string)s.Attribute("name"),
                                 ZthList = s.Elements("zth")
                                            .Select(r => new Zth()
                                            {
                                                m_node = (string)r.Attribute("m_node"),
                                                d_node = (string)r.Attribute("d_node"),
                                                time = (string)r.Element("data").Attribute("time"),
                                                value = (string)r.Element("data").Attribute("value")
                                            }).ToList()
                             }).ToList();
            List<Scenario> zth_d_node = scenarios.Where(x => x.ZthList.Any(r => r.d_node == "1")).ToList();
            List<Scenario> s_names = scenarios.Where(x => x.name == "name").ToList();

            Console.WriteLine("List: ");
            Console.WriteLine(String.Join(", ", scenarios.Select(x => x.name )));
        }
    }
}

enter image description here

4 Comments

In this line List<Scenario> zth_d_node = scenarios.Where(x => x.ZthList.Any(r => r.d_node == "1")).ToList(); I was trying to create another list where I "filter" through the zth elements and check if d_node is one, if this is the case I want to save the time values of the element data. How can I save these values in a list, the code that I tried just displays only "true" values, but not the actual data.
You are seeing the results of the WHERE (which is either true or false). You need a SELECT after the WHERE to return data.
Can you be a bit more specific. How can I select the time attribute from data in this case?
It is already these. I added a picture to my answer so you can see.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.