使用C#4.0动态的XML导航和阅读?

时间:2010-07-28 00:16:22

标签: xml c#-4.0 dynamic linq-to-xml dynamic-language-runtime

.NET 4.0中是否提供支持DLR的XML导航和阅读课程?例如,假设我有这个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之前的世界。

例如,“dot”运算符可以检查子元素名称之前的属性名称。或者非收集操作会自动应用于第一个元素(就像jQuery一样)。

.NET 4.0 Framework类库是否包含这样的内容?如果没有,建议一个好的开源项目或支持DLR的XML库的样本?

1 个答案:

答案 0 :(得分:2)

我做了一点测试:

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,但您必须对所有lambdas进行限定:

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

那就是说,如果您只是从这样的XML树中提取值,我认为它可以正常工作。