views:

234

answers:

2

I was trying out parsing XML using Fluent interface as described here.

The example is good but gives one compiler error that I am not able to fix.

The error is in the protected constructor below:

protected DynamicXml( IEnumerable<XElement> elements )
{
    _elements = new List<XElement>( elements ); // error on this line
}

The two compiler errors I get on this line are:

 Argument 1: cannot convert from 
'System.Collections.Generic.IEnumerable<System.Xml.Linq.XElement>' to   
'System.Xml.Linq.XElement'

and

The best overloaded Add method    
'System.Collections.Generic.List<System.Xml.Linq.XElement>.
Add(System.Xml.Linq.XElement)' for the collection initializer 
has some invalid arguments

I have copy/pasted the full code below:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Dynamic;
using System.Xml.Linq;
using System.Collections;

namespace FluentXML
{
    public class DynamicXml : DynamicObject, IEnumerable
    {
        private readonly List<XElement> _elements;

        public DynamicXml(string text)
        {
            var doc = XDocument.Parse(text);
            _elements = new List<XElement> { doc.Root };
        }

        protected DynamicXml(XElement element)
        {
            _elements = new List<XElement> { element };
        }

        protected DynamicXml(IEnumerable<XElement> iteratorElem)
        {
            _elements = new List<XElement> { iteratorElem };
        } 

        public override bool TryGetMember(GetMemberBinder binder, out object result)
        {
            result = null;
            if (binder.Name == "Value")
                result = _elements[0].Value;
            else if (binder.Name == "Count")
                result = _elements.Count;
            else
            {
                var attr = _elements[0].Attribute(
                    XName.Get(binder.Name));
                if (attr != null)
                    result = attr;
                else
                {
                    var items = _elements.Descendants(
                        XName.Get(binder.Name));
                    if (items == null || items.Count() == 0)
                        return false;
                    result = new DynamicXml(items);
                }
            }
            return true;
        }

        public override bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object result)
        {
            int ndx = (int)indexes[0];
            result = new DynamicXml(_elements[ndx]);
            return true;
        }

        public IEnumerator GetEnumerator()
        {
            foreach (var element in _elements)
                yield return new DynamicXml(element);
        }
    }
}

namespace FluentXML
{
    class Program
    {
        static void Main(string[] args)
        {
            string xmlString = FluentXML.Properties.Resources.InputString;
            dynamic dx = new DynamicXml(xmlString);
            Console.WriteLine("PublicationDate='{0}'", dx.pubdate.Value);
            Console.WriteLine("BookCount='{0}'", dx.book.Count);
            foreach (dynamic d in dx.book)
            {
                Console.WriteLine("----- Begin Book -----");
                Console.WriteLine("Price='{0}'", d.price.Value);
                Console.WriteLine("Title='{0}'", d.title.Value);
                Console.WriteLine("AuthorCount='{0}'", d.authors.author.Count);
                foreach (dynamic a in d.authors.author)
                {
                    Console.WriteLine("   ---- Begin Author ----");
                    Console.WriteLine("   EmailAddress='{0}'", a.email.address.Value);
                    Console.WriteLine("   FirstName='{0}'", a.name.first.Value);
                    Console.WriteLine("   MiddleName='{0}'", a.name.middle.Value);
                    Console.WriteLine("   LastName='{0}'", a.name.last.Value);
                    Console.WriteLine("   ----- End Author -----");
                }
                Console.WriteLine("------ End Book ------");
            }
        }
    }
}
+3  A: 
    protected DynamicXml(IEnumerable<XElement> iteratorElem)
    {
        _elements = new List<XElement> { iteratorElem };
    }

is the sequence initializer. This would create a list with one element "iteratorElem" which isn't of type XElement (as the error says).

Calling:

    protected DynamicXml(IEnumerable<XElement> iteratorElem)
    {
        _elements = new List<XElement>(iteratorElem);
    }

should work, though. You could also write iteratorElem.ToList()

nikie
+3  A: 

The protected constructor that you posted in the first code sample is not the same as the one you posted in the second code sample...

This one will work!

protected DynamicXml( IEnumerable<XElement> elements )
{
    _elements = new List<XElement>( elements ); // error on this line
}

This one will not! :(

protected DynamicXml(IEnumerable<XElement> iteratorElem)
{
    _elements = new List<XElement> { iteratorElem };
}

The difference is the use of parentheses vs an initializer block (not sure if that is the technical term). The parenthesized version will call the generic List constructor overload that takes a generic IEnumerable as a parameter. The version with the braces will attempt to add the generic IEnumerable as a single element in the list.

Chris Shouts