2

Here is my problem:

I have this XML file:

<?xml version="1.0" encoding="utf-8" ?>
<settings>
  <app name="Application1">
    <log name="Log1" path="d:\paths\" filename="Log1File"/>
    <log name="Log2" path="d:\paths\"/>
    <log name="log3" path="d:\paths\" filename="Log3File"/>
  </app>
</settings>

And I'm trying to read it with LINQ and create object of this class:

  public class Apps
  {
    public string Name { get; set; }
    public IEnumerable<Logs> Logs { get; set; }
  }

  public class Logs
  {
    public string Name { get; set; }
    public string Path { get; set; }
    public string Filename { get; set; }
  }

So far I managed to create this bit of code however looks like it only gets first log element mean time I need all log elements for each app element:

   public static IEnumerable<Apps> GetAllApps()
    {
      var items = from a in db.Descendants("app")
                  orderby a.Attribute("name").Value
                  select new Apps
                  {
                    Name = a.Attribute("name").Value,
                    Logs = from b in a.Descendants("log")
                           select new Logs 
                           { 
                            Name = b.Attribute("name").Value,
                            Path = b.Attribute("path").Value,
                            Filename = b.Attribute("filename").Value
                           }
                  };

      return items;
    }
0

2 Answers 2

3

I would use serialization here

XmlSerializer ser = new XmlSerializer(typeof(Settings));
var result = (Settings)ser.Deserialize(stream);

[XmlRoot("settings")]
public class Settings
{
    [XmlElement("app")]
    public Apps[] apps;
}


public class Apps
{
    [XmlAttribute("name")]
    public string Name { get; set; }
    [XmlElement("log")]
    public Logs[] Logs { get; set; }
}

public class Logs
{
    [XmlAttribute("name")]
    public string Name { get; set; }
    [XmlAttribute("path")]
    public string Path { get; set; }
    [XmlAttribute("filename")]
    public string Filename { get; set; }
}
Sign up to request clarification or add additional context in comments.

1 Comment

This is usually the better solution. If you have a stable/proper xml schema, you can even generate your boilerplate code with xsd.exe. As it generates partial classes by default, you can have them implement you domain interfaces and thus further reduce the dependencies from the actual xml code.
0

I used fluent API, but let you adapt as you prefer...

Problem is a NullReferenceException, as one of your Logs in xml has no "filename" attribute. And when you use "Value" on a null, you get a NRE.

So, check if the Attribute exists before trying to get it's value.

var it = db.Descendants("app")
                    .OrderBy(app => app.Attribute("name").Value)
                    .Select(app => new Apps() {
                        Name = app.Attribute("name").Value,
                        Logs = app.Descendants("log").Select(a =>
                            new Logs() {
                                Name = a.Attribute("name") != null ? a.Attribute("name").Value : null,
                                Path = a.Attribute("path") != null ? a.Attribute("path").Value : null,
                                Filename = a.Attribute("filename") != null ? a.Attribute("filename").Value : null
                            }).ToList()
                    }).ToList();

Comments

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.