XML навигация и чтение с использованием C # 4.0 динамически? - PullRequest
3 голосов
/ 28 июля 2010

Существует ли в .NET 4.0 класс навигации и чтения XML с поддержкой DLR? Например, представьте, что у меня есть этот XML:

<foo>
   <bar>foobar is here</bar>
   <bar>foobar is also here</bar>
   <baz>foobar is not here</bar>
</foo>

Существует ли простой способ навигации по этому XML, например так:

var doc = SomeDlrEnabledParser.Parse (xmlString);
foreach (var node in doc.foo.bar)
{
    if (node == "foobar is here")
        DoSomething();
    else
        DoSomethingElse();
}

Я вижу множество причин, по которым вышеуказанный подход может быть проблематичным, в том числе пространства имен, атрибуты и элементы, различение коллекций и отдельных элементов, кодированный XML и текст и т. Д.

Но большая часть XML, с которой я имею дело, очень проста и доступна только для чтения, и я был бы готов принять разумное поведение по умолчанию в обмен на то, чтобы избежать "скобок и супа кавычек", которые характерны для работы с простым XML в мир до 4.0.

Например, оператор «точка» может проверять имена атрибутов перед именами подэлементов. В противном случае операции, не связанные с коллекцией, будут автоматически применяться к первому элементу (как это делает jQuery).

Содержит ли библиотека классов .NET 4.0 Framework что-то подобное? если нет, какие-либо рекомендации для хорошего проекта с открытым исходным кодом или образец библиотеки XML с поддержкой DLR?

1 Ответ

2 голосов
/ 28 июля 2010

Я сделал небольшой тест реализации:

public class DynamicXml : DynamicObject, IEnumerable<XNode>
{
    private readonly IEnumerable<XNode> nodes;

    public DynamicXml(params XNode[] nodes)
    {
        this.nodes = nodes;
    }

    public override bool TryGetMember(GetMemberBinder binder, out object result)
    {
        var children = nodes.OfType<XContainer>().SelectMany(node => node.Elements(binder.Name)).Cast<XNode>().ToArray();
        result = new DynamicXml(children);
        return true;
    }

    public IEnumerator<XNode> GetEnumerator()
    {
        return nodes.GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
}

И пример:

class Program
{
    static void Main(string[] args)
    {
        dynamic dynDoc = new DynamicXml(XDocument.Parse(
            @"<foo>
                <bar>foobar is here</bar>
                <bar>foobar is also here</bar>
                <baz>foobar is not here</baz>
              </foo>"));

        foreach (XElement node in dynDoc.foo.bar)
        {
            if (node.Value == "foobar is here")
                Console.WriteLine("found: {0}", node);
            else
                Console.WriteLine("not found: {0}", node);
        }

        Console.ReadKey(true);
    }
}

Однако, похоже, что интерфейс между этим и некоторым другим кодом не так хорош.

Например, если мы хотим использовать Linq против узлов, мы должны сначала явно привести к IEnumerable ... в противном случае наш Where будет интерпретирован как имя элемента.

((DynamicXml)dynXml.foo.bar).Where(x => x.Value == "foobar is here");

Вы можете реализовать Where непосредственно для динамического типа, но затем вы должны квалифицировать все лямбды следующим образом:

foo.bar.Where((Func<XElement,bool>)(x => x.Value == "foobar is here")) 

Тем не менее, если вы просто извлекаете значения из дерева XML, как это, я думаю, что это работает нормально.

...