views:

488

answers:

2

I recently asked a question regarding how to Save a list with nested elements to XML but now I am trying to write the loader for the class and have run into problems with it.

I am attempting to reverse the answer given (thanks Jon).

I believe my core LINQ query is ok, it is the recursion I am struggling with. Here is my code so far (for clarity's sake I have posted the entire CPP as is)

   /// <summary>
/// 
/// </summary>
public class ErrorType
{
    List<ErrorType> _childErrors;

    public String Name { get; set; }
    public bool Ignore { get; set; }

    public List<ErrorType> ChildErrors { get; protected set; }
}

/// <summary>
/// 
/// </summary>
public class ErrorList
{
    public List<ErrorType> ChildErrors { get; protected set; }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="xml"></param>
    public void FilterErrors(XElement xml)
    {
        //Convert to ErrorList
        //Write back out to XML but not writing out anything with errors
        //Send XML on its way
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="el"></param>
    /// <returns></returns>
    private XElement ErrorListToXml(ErrorList el)
    {
        // Need to declare in advance to call within the lambda.
        Func<ErrorType, XElement> recursiveGenerator = null;
        recursiveGenerator = error => new XElement
            (error.Name,
             new XAttribute("Ignore", error.Ignore),
             error.ChildErrors.Select(recursiveGenerator));

        var element = new XElement
                   ("ErrorList",
                    ChildErrors.Select(recursiveGenerator));

        Console.WriteLine(element);

        return element;
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="xd"></param>
    /// <returns></returns>
    private ErrorList FromXmlToErrorList(XElement xd)
    {
        //Prepare lambda
        Func<ErrorType, XElement> recursiveGenerator = null;
        recursiveGenerator = error => new List<ErrorType>
            (error.Name,
             new XAttribute("Ignore", error.Ignore),
             error.ChildErrors.Select(recursiveGenerator));

        List<ErrorType> typeList = (from error in xd.Descendants()
                        select new ErrorType
                        {
                            Name = error.Value,
                            Ignore = bool.Parse(error.Attribute("Ignore").Value),
                            ChildErrors= error.Elements().Select()
                        }).ToList<ErrorType>();

        ErrorList el = new ErrorList();
        el.ChildErrors = typeList;
        return el;
    }

    /// <summary>
    /// 
    /// </summary>
    public void Save()
    {
        XElement xml = ErrorListToXml(this);
        xml.Save("errorlist.xml");
    }

    public void Load()
    {

    }
}

Thankyou

+2  A: 

I got it working with something like:

    XDocument doc = XDocument.Parse(xml);

    Func<XElement, ErrorType> nodeReader = null;
    nodeReader = el => new ErrorType(
        el.Elements().Select(nodeReader)) {
        Name = el.Name.LocalName,
        Ignore = (bool)el.Attribute("Ignore"),
    };

    ErrorList list = new ErrorList(
        doc.Root.Elements().Select(nodeReader));

Having added suitable constructors:

public ErrorType(IEnumerable<ErrorType> children) {
    ChildErrors = new List<ErrorType>(children);
}
public ErrorType() { ChildErrors = new List<ErrorType>(); }

public ErrorType(IEnumerable<ErrorType> children) {
    ChildErrors = new List<ErrorType>(children);
}
public ErrorType() { ChildErrors = new List<ErrorType>(); }

any use?

Marc Gravell
This worked very nicely thankyou. I'm not entirely sure how it works though as it never explicitly sets the children?
Chris
The constructor itself creates the children - by iterating the "children" parameter, which is (behind the scenes) an iterator over the xml...
Marc Gravell
Ahh I had code blindness and didnt see you pass the list into the ctor in the function. Nice work mate thanks
Chris
+1  A: 

Okay, I haven't tried this (and don't have time to right now) but I think it should pretty much work...

public class ErrorType
{
    List<ErrorType> _childErrors;

    public String Name { get; set; }
    public bool Ignore { get; set; }

    public List<ErrorType> ChildErrors { get; protected set; }

    public static ErrorType Parse(XElement element)
    {
        return new ErrorType
        {
            Name = element.Name.LocalName,
            Ignore = (bool) element.Attribute("Ignore"),
            ChildErrors = element.Elements()
                                 .Select(x => Parse(x))
                                 .ToList()
        };
    }
}

public class ErrorList
{
    public List<ErrorType> ChildErrors { get; protected set; }

    public static ErrorList Parse(XElement element)
    {
        return new ErrorList { ChildErrors = element.Elements()
                                 .Select(x => ErrorType.Parse(x))
                                 .ToList() };
    }
}
Jon Skeet
Thanks for the reply Jon but I couldn't get it working. Probably a combination of you rushing and my inability to stitch together what you tried to do.
Chris
Fixed - should be okay now.
Jon Skeet