通过递归构建XML与动态的XElement [英] Building Xml with XElement dynamically through recursion

查看:105
本文介绍了通过递归构建XML与动态的XElement的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是新来的LINQ to XML。结果
我有一个递归方法,得到的参数的XElement根应保持在XML数据的方式,将表示给定递归深度的相关子树的根。

I'm new to linq to Xml.
I have a recursive method which get as parameter XElement root which should hold the XML data in a way it will represent the correlating subtree root of a given recursion depth.

无效recursiveMethod(根的XElement); 结果
更具体地讲,还看这个XML例子:

void recursiveMethod(XElement root);
To be more specific,also look at this XML example:

<start>
      <Class>
           <Worker>
                <Name> Dan </Name>
                <Phone> 123 </Phone> 
                <Class>
                      <Address>
                           <Street> yellow brick road </Street>
                           <Zip Code> 123456 </Zip Code>
                      </Address>
                </Class>
            </Worker>
      </Class>
...
</start>    



你可以想像,名称是值而类型地址是一个类引用。结果
XML信息应通过反射动态添加(以自上而下的方法)。

As you can imagine, Name is value type whereas Address is a class reference.
The Xml information should be added dynamically through reflection ( in top down approach).

为了使长话短说想象,我在调查工人类的中间,达到地址类,并想深入,所以我想打电话给我递归方法与当前Worker类为新的XElement根的子节点的正确的参考,所以我会能够在地址一类递归深度下面给它添加什么,我发现通过反射。

To make the long story short imagine that I'm in the middle of investigating Worker Class and reached Address Class and want to "drill down", so I want to call my recursive method with the right reference of child nodes of the current Worker class as the new XElement root, so I will be able to add to it what I found by reflection in the Address Class one recursion depth below.

请注意,这个基准应该是的XElement类型。

Note that this reference should be of XElement type.

我怎么能做到这一点。

修改:如果你有另一个想法做这一切的东西,但不能与的XElement 的我会很高兴听到同样,虽然我的XElement 参数

EDIT: If you have another idea of doing all this stuff but not with XElement I'll be happy to hear about also, although I prefer it with XElement parameter.

另一个问题:结果
我已经开始在一个天真的方式来实现它想通过各个领域的迭代,如果我有encounterd值类型(IsValueType)(字段信息[]的变量),我在做类似

Another issue:
I've started implementing it in a naive way like iterating through all fields (variable of FieldInfo[]), and if I had encounterd value type(IsValueType) I was doing something like

 root.Add(new XElement("Field",
                      new XElement("Type", ...),
                      new XElement("Variable Name", ...),
                      new XElement("Value", ...)));     



所以,只是一般知识:结果
1.是否有办法得到其decendants节点的唯一参考,这样,在较低的递归级别我就可以做一套root.Add(...)同上,但这个根将是以前的根儿童的参考? (这意味着在做整个操作没有Linq的语法)

So ,just for general knowledge:
1. Was there a way to get only the reference of a node to its decendants ,so that in lower recursion level I'll be able to do another root.Add(...) as above but this root will be a reference to children of previous root? (Which means doing the whole operation without Linq syntax)

2.I've设法私有字段通过反射值,而不包含属性的工作,是有问题的? ?我应该始终贯穿性采取反射值

2.I've managed to get private fields value through reflection without working with properties, is it problematic? Should I always take values through properties in reflection?

推荐答案

这个扩展方法将在需要的格式建立的XElement:

This extension method will build XElement in required format:

public static class Extensions
{
    public static XElement ToXml<T>(this T obj)
    {
        Type type = typeof(T);

        return new XElement("Class",
                    new XElement(type.Name,
                        from pi in type.GetProperties()
                        where !pi.GetIndexParameters().Any()
                        let value = (dynamic)pi.GetValue(obj, null)
                        select pi.PropertyType.IsPrimitive || 
                               pi.PropertyType == typeof(string) ?
                                new XElement(pi.Name, value) : 
                                Extensions.ToXml(value)
                        )
                    );
    }
}



在这里发生什么:

What happens here:


  • 我们得到传递的对象的公共属性(可以添加的BindingFlags筛选属性)。

  • 接下来,我验证,如果酒店有指标参数,并跳过这样的属性。

  • 接下来,我得到属性值动态对象。这一点很重要,否则属性值类型将被推断为对象的递归调用过程中 toxml用于< T>

  • 我检查,如果属性类型是基本类型(INT,字节,长的,单,双,等)或字符串

  • 对于我们写元素和基本类型属性值。对于其他类型的(复杂),我们递归地开始建设的XElement

  • We get public properties of passed object (you can add BindingFlags to filter properties).
  • Next I verify if property has index parameters and skip such properties.
  • Next I get property value as dynamic object. It's important, otherwise property value type will be inferred as object during recursive call of ToXml<T> method.
  • I check if property type is primitive type (int, byte, long, single, double, etc) or string
  • For primitive types we write element with property value. For other types (complex) we recursively start building XElement

用法:

Worker worker = new Worker()
{
    Name = "Serge",
    Phone = "911",
    Address = new Address() { Street = "Elm street", ZipCode = 666 }
};

XElement xml = worker.ToXml();



结果:

Result:

<Class>
  <Worker>
    <Name>Serge</Name>
    <Phone>911</Phone>
    <Class>
      <Address>
        <Street>Elm street</Street>
        <ZipCode>666</ZipCode>
      </Address>
    </Class>
  </Worker>
</Class>



BUT 你应该小心情况下,当两个物体指对方的(无限递归会在这种情况下发生的)

BUT you should be careful with situations when two objects refer each other (infinite recursion will happen in this case)

在这种情况下,你可以使用类似字典或HashSet的存储其中已经存在的所有对象的XML:

In this case you can use something like dictionary or hashset to store all objects which already exist in your xml:

Type type = obj.GetType();
if (set.Contains(obj))
    return new XElement("Class", new XAttribute("name", type.Name));
set.Add(obj);
return new XElement("Class", ...);

这篇关于通过递归构建XML与动态的XElement的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆