LinqToXml:根据管理层次结构对用户节点重新排序

本文关键字:新排序 排序 节点 用户 管理 层次结构 LinqToXml | 更新日期: 2023-09-27 18:35:50

我有一个来自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,因为建议部分有效。 它以前是无效的,因为有一个循环引用。

LinqToXml:根据管理层次结构对用户节点重新排序

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

此选项将为您提供一个排序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);

注意:这应该按层次结构中的"报告级别"对它们进行排序,但不会显示他下面列出的经理下的人员 - 即:所有向高层经理报告的人都将首先显示,然后是所有向二级经理报告的人,等等......