展平父/子层次结构

时间:2014-04-09 18:48:24

标签: c# xml linq linq-to-xml

我试图在这里理解一个概念:

来自像

这样的对象结构
class Parent
{
    public string ParentID { get; set; }
    public List<Child> Children { get; set; } 
}

class Child
{
   public string ChildID { get; set; }
}

假设一个完全填充的父对象,我想使用Linq to Xml来获取以下Xml输出:

<Mappings>
   <Mapping ID='ParentID1' ChildID='ChildID1'>
   <Mapping ID='ParentID1' ChildID='ChildID2'>
</Mappings>

如何展开嵌套的原始对象以获取此映射列表?

修改

父母的例子如:

ParentID = 'Parent1', Children = new [] { "Child1", "Child2", "Child3" }

我期待3次映射:

<Mapping ID='Parent1' ChildID='Child1' />
<Mapping ID='Parent1' ChildID='Child2' />
<Mapping ID='Parent1' ChildID='Child3' />

1 个答案:

答案 0 :(得分:0)

修改

以下代码将展平层次结构:

var list = new List<Parent>
{
    new Parent
    {
        ParentID = "parentID1",
        Children = new List<Child> {new Child {ChildID = "childID1"}, new Child {ChildID = "childID2"}}
    },
    new Parent
    {
        ParentID = "parentID2",
        Children = new List<Child> {new Child {ChildID = "childID3"}, new Child {ChildID = "childID4"}}
    }
};

IEnumerable<XElement> list1 = (from parent in list
    from child in parent.Children
    select
        new XElement("Mapping", new XAttribute("ID", parent.ParentID),
            new XAttribute("ChildID", child.ChildID)));

string @join = string.Join(Environment.NewLine, list1);

输出:

<Mapping ID="parentID1" ChildID="childID1" />
<Mapping ID="parentID1" ChildID="childID2" />
<Mapping ID="parentID2" ChildID="childID3" />
<Mapping ID="parentID2" ChildID="childID4" />

以下是如何实现它的示例:

注意:这不会起作用,它会产生一个例外,说明“重复属性”

List<Parent> list = new List<Parent>
{
    new Parent() {ParentID = "parentID1", Children = new List<Child>() {new Child() {ChildID = "childID1"},new Child() {ChildID = "childID2"}}},
    new Parent() {ParentID = "parentID2", Children = new List<Child>() {new Child() {ChildID = "childID3"},new Child() {ChildID = "childID4"}}}
    };
IEnumerable<string> enumerable = xElements.Select(s => s.ToString());


IEnumerable<XElement> xElements = list.Select(s => new XElement("Mapping", new XAttribute("ID", s.ParentID), s.Children.Select(t => new XAttribute("ChildID", t.ChildID))));
IEnumerable<string> enumerable = xElements.Select(s => s.ToString());
var @join = string.Join(Environment.NewLine, enumerable);

这个会因为它将使用Select的重载使用当前对象的索引:

var list = new List<Parent>
{
    new Parent
    {
        ParentID = "parentID1",
        Children = new List<Child> {new Child {ChildID = "childID1"}, new Child {ChildID = "childID2"}}
    },
    new Parent
    {
        ParentID = "parentID2",
        Children = new List<Child> {new Child {ChildID = "childID3"}, new Child {ChildID = "childID4"}}
    }
};

IEnumerable<XElement> xElements =
    list.Select(
        s =>
            new XElement("Mapping", new XAttribute("ID", s.ParentID),
                s.Children.Select((t, u) => new XAttribute(string.Format("ChildID_{0}", u), t.ChildID))));
var @join = string.Join(Environment.NewLine,xElements);

结果:不是你所期待的,对吗?

<Mapping ID="parentID1" ChildID_0="childID1" ChildID_1="childID2" />
<Mapping ID="parentID2" ChildID_0="childID3" ChildID_1="childID4" />

为什么我使用了这个重载?

因为父母有一个孩子的列表,而第一个代码可以与一个孩子一起使用,但不会有很多孩子。

结论:

不确定你想要实现的目标,

为什么不直接保持对象的结构?