通过递归动态构建带有XElement的Xml

Jav*_*aSa 2 c# xml linq reflection linq-to-xml

我是linq to Xml的新手.
我有一个递归方法,它获取as参数XElement root,该方法应该以某种方式保存XML数据,它将表示给定递归深度的相关子树根.

void recursiveMethod(XElement root);
更具体地说,还要看一下这个XML示例:

<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>    
Run Code Online (Sandbox Code Playgroud)

您可以想象,Name是值类型,Address而是类引用.
应通过反射动态添加Xml信息(自顶向下方法).

总而言之,想象一下,我正在调查WorkerClass并达到AddressClass并希望"向下钻取",所以我想用当前Worker类的子节点的正确引用来调用我的递归方法作为新的XElement根,所以我将能够添加我在Address下面的一级递归深度中通过反射找到的内容.

请注意,此引用应为XElement类型.

我怎样才能做到这一点?

编辑:如果你有另一个想法做所有这些,但不是XElement我也会很高兴听到,虽然我更喜欢它与XElement参数.

另一个问题:
我已经开始以一种天真的方式实现它,比如遍历所有字段(FieldInfo []的变量),如果我遇到了值类型(IsValueType),我就是这样做的

 root.Add(new XElement("Field",
                      new XElement("Type", ...),
                      new XElement("Variable Name", ...),
                      new XElement("Value", ...)));     
Run Code Online (Sandbox Code Playgroud)

所以,只是为了一般知识:
1.有没有办法只获得一个节点的引用到它的后代,所以在较低的递归级别,我将能够做另一个root.Add(...),但如上所述这个root将是对以前root的孩子的引用?(这意味着在没有Linq语法的情况下进行整个操作)

2.我设法通过反射获得私有字段的价值,而无需使用属性,是否有问题?我应该总是通过反射中的属性来获取值吗?

Ser*_*kiy 5

此扩展方法将以所需格式构建XElement:

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)
                        )
                    );
    }
}
Run Code Online (Sandbox Code Playgroud)

这里发生了什么:

  • 我们获取传递对象的公共属性(您可以添加BindingFlags来过滤属性).
  • 接下来,我验证属性是否具有索引参数并跳过此类属性.
  • 接下来,我将属性值作为dynamic对象.这很重要,否则属性值类型将objectToXml<T>方法的递归调用期间被推断.
  • 我检查属性类型是基本类型(int,byte,long,single,double等)还是字符串
  • 对于原始类型,我们使用属性值编写元素.对于其他类型(复杂),我们递归地开始构建XElement

用法:

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

XElement xml = worker.ToXml();
Run Code Online (Sandbox Code Playgroud)

结果:

<Class>
  <Worker>
    <Name>Serge</Name>
    <Phone>911</Phone>
    <Class>
      <Address>
        <Street>Elm street</Street>
        <ZipCode>666</ZipCode>
      </Address>
    </Class>
  </Worker>
</Class>
Run Code Online (Sandbox Code Playgroud)

但是 当两个对象相互引用时应该小心(在这种情况下会发生无限递归)

在这种情况下,您可以使用类似字典或散列集的内容来存储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", ...);
Run Code Online (Sandbox Code Playgroud)

  • @JavaSa 抱歉,现在需要走了,但我认为最好为另一个问题开始新问题 (2认同)