Linq To Xml:根据管理层次结构重新排序用户节点

时间:2013-10-18 08:54:24

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

我有来自LDAP(活动目录)的用户及其经理的输出xml,如下所示。我需要重新排序用户,以便在创建用户时按照管理层次结构的顺序创建用户。用户和管理器子节点中的dn字段是链接值。这样,当我们的用户导入例程处理它们时,我们不必在尚未创建管理器时为用户分配管理器。这对Linqtoxml有用吗?

 <?xml version="1.0" encoding="utf-8"?>
<syncdata>
    <users> 
        <user>
            <dn>User2</dn>   
            <manager><dn>User1</dn></manager>
        </user>
        <user>
            <dn>User1</dn>   
            <manager><dn>User5</dn></manager>
        </user>  
        <user>
            <dn>User4</dn>   
            <manager><dn>User1</dn></manager>
        </user>
        <user>
            <dn>User5</dn>   
            <manager><dn>User3</dn></manager>
        </user>
        <user>
            <dn>User3</dn>   
            <manager><dn></dn></manager>
        </user>
    </users>
</syncdata>  

更新:重新格式化xml,因为建议部分工作。因为有一个循环引用,它之前是无效的。

2 个答案:

答案 0 :(得分:1)

    var element = XElement.Load(yourXmlPath);

    var ordered=element.Element("users").Elements().OrderBy(u => u.Element("manager").Element("dn").Value);

    element.Element("users").ReplaceAll(ordered);

答案 1 :(得分:1)

此选项将为您提供已排序的IOrderedEnumerable,其中包含每个用户的xml和managerId。这种变化应该给你很大的灵活性:

var sortedUsers =
     yourRootXElement.Element("users")
                     .Elements()
                     .Select(usr => 
                               new {
                                     managerId = usr.Element("manager")
                                                    .Element("dn")
                                                    .Value, 
                                     user = usr
                                    }) 
                     .OrderBy(user => user.managerId);

<强>更新

基于其他一个答案下的评论,您似乎想要“递归”(有点)重新排序。

最初,使用Linq并不是那么容易 - 除非您可以选择操作原始XML,否则最好为此编写递归算法。

但是,如果您可以向XML中的每个用户添加一个字段depth,那么它看起来就像这样......:

<syncdata>
    <users> 
        <user>
            <dn>User2</dn>   
            <manager><dn>User1</dn></manager>
            <depth>2</depth>

        </user>
        <user>
            <dn>User1</dn>   
            <manager><dn>User5</dn></manager>
            <depth>1</depth>
        </user>  
        <user>
            <dn>User4</dn>   
            <manager><dn>User1</dn></manager>
            <depth>2</depth>
        </user>
        <user>
            <dn>User5</dn>   
            <manager><dn>User3</dn></manager>
            <depth>1</depth>
        </user>
        <user>
            <dn>User3</dn>   
            <manager><dn></dn></manager>
            <depth>0</depth> <!-- Note: Root element in hierarchy! -->
        </user>
    </users>
</syncdata>

...那么您可以按如下方式订购?:

var sortedUsers =
    yourRootXElement.Element("users")
                    .Elements()
                    .Select(usr => 
                                new {
                                    userId =  usr.Element("dn").Value,
                                    managerId = usr.Element("manager")
                                                   .Element("dn")
                                                   .Value,
                                    depth = usr.Element("depth")
                                               .Value,
                                    userData = usr
                                })
                    .OrderBy(user => user.depth)
                    .ThenBy(user => user.managerId);

注意:这应按照层次结构中的“报告级别”对其进行排序,但不会在其下列出的经理下显示 - 即:所有向顶级报告的人将首先展示管理人员,然后是向二级管理人员报告的所有人员......