将一组父子关系转换为层次结构

时间:2016-03-02 13:53:56

标签: perl

我有一个我正在使用Net::LDAP查询的LDAP目录。这给了我一组亲子关系。

这是一个人的目录 - 并包含一个'经理'DN(这是目录中的另一个字段)。

我真的遇到了将此经理 - >人员记录集转换为层次结构的问题。

到目前为止我得到的是:

#!/usr/bin/env perl
use strict;
use warnings;
use Net::LDAP;
use Data::Dumper;

my %people;

my $ldap   = Net::LDAP->new('my_ldap_server');
my $result = $ldap->bind('bind_dn');
die if $result->code;

my $search = $ldap->search(
    base   => 'ou=yaddayadda',
    scope  => 'subtree',
    filter => 'objectClass=person',
    attrs  => ['manager'],
);
foreach my $found ( $search->entries ) {
    my $mgr = $found->get_value('manager');
    my $dn  = $result->dn;
    push( @{ $people{$mgr} }, $dn );
}

这给了我一个经理人和为他们工作的人(使用DN,这是唯一的)。

来自%people的条目如下:

$VAR1 = { 
            'cn=Firstname Lastname,ou=OrgUnit' => [
                          'cn=Personame Lastname,ou=OrgUnit',
                          'cn=AnotherPerson NameHere,ou=OrgUnit', 
                         ],
            'cn=AnotherPerson NameHere,ou=OrgUnit' => [
                         'cn=Someone Else,ou=OrgUnit', 
                         ]
           };

但我将把父子映射转换为层次结构时遇到了麻烦。

e.g:

'ceo' => [
             'pa' => [],
             'head_of_dept' => [ 
                       'person' => [],
                       'person_with_staff' => [ 'person3', 'person4' ]
                    ]
          ]

我对如何实现这一点感到茫然。考虑到每个人在组织结构中都是独一无二的,这似乎不应该太难。

注意 - 在上面,我有cn=AnotherPerson NameHere,ou=OrgUnit谁有一个下属,我正在制作一个嵌套的映射:

e.g:

$VAR1 = {
          'cn=Firstname Lastname,ou=OrgUnit' => [
                                                  'cn=Personame Lastname,ou=OrgUnit',
                                                  'cn=AnotherPerson NameHere,ou=OrgUnit',
                                                  [
                                                    'cn=Someone Else,ou=OrgUnit'
                                                  ]
                                                ]
        };

2 个答案:

答案 0 :(得分:3)

您需要的是有向图,我建议使用Graph::Directed模块,其方法记录在Graph

这个程序会为你构建图形,但没有任何数据我无法测试它,除了确保它编译

$('#frmInventario').submit(function () {
                debugger;
               var oTable =  $('#TableId').dataTable();
                oTable.fnFilter("");
                var oSettings = oTable.fnSettings();
                oSettings._iDisplayLength = -1;
                oTable.fnDraw();


            });

生成的use strict; use warnings 'all'; use feature 'say'; use Net::LDAP; use Graph::Directed; use Data::Dumper; my $ldap = Net::LDAP->new('my_ldap_server'); my $result = $ldap->bind('bind_dn'); die if $result->code; my $search = $ldap->search( base => 'ou=yaddayadda', scope => 'subtree', filter => 'objectClass=person', attrs => ['manager'], ); my $g = Graph::Directed->new; for my $found ( $search->entries ) { my $mgr = $found->get_value('manager'); my $dn = $result->dn; $g->add_edge($mgr, $dn); } say $g; 对象具有字符串化重载,因此您可以通过简单地打印它来表面检查它,但是当您想要进一步询问结构时,您需要知道graph theory的一些术语。 。例如,Graph::Directed将返回所有具有后代但没有父级的节点的列表 - 在这种情况下,是高级管理人员列表,或$g->source_vertices将返回 true 如果您的数据在任何地方都有任何循环


这是一个程序示例,它使用您的简短示例数据来显示节点的分层树

$g->is_cyclic

输出

use strict;
use warnings 'all';
use Graph::Directed;

my $data = {
    'cn=Firstname Lastname,ou=OrgUnit' => [
        'cn=Personame Lastname,ou=OrgUnit',
        'cn=AnotherPerson NameHere,ou=OrgUnit',
    ],
    'cn=AnotherPerson NameHere,ou=OrgUnit' =>
        [ 'cn=Someone Else,ou=OrgUnit', ]
};

my $g = Graph::Directed->new;

for my $mgr ( keys %$data ) {
    $g->add_edge($mgr, $_) for @{ $data->{$mgr} };
}

dump_tree($_) for $g->source_vertices;


sub dump_tree {
    my ($node, $level) = ( @_, 0);
    print '   ' x $level, $node, "\n";
    dump_tree($_, $level+1) for $g->successors($node);
}

答案 1 :(得分:2)

@Hunter McMillen unfortunately deleted his very good but slightly off answer。这是我试图通过改变 underling - >之间的关系来增强他的代码。老板走向老板 - >下属

为了模拟LDAP响应,我创建了一个简单的Moose类。

package Person;
use Moose;

has name => ( is => 'ro' );
has boss => ( is => 'ro', predicate => 'has_boss' );

package main;
use strict;
use warnings;
use Data::Printer;

# make a randomized list of people
my %people = map { $_->name => $_ }
    map { 
      Person->new( 
        name => $_->[0], ( $_->[1] ? ( boss => $_->[1] ) : () ) 
      ) 
    } (
      [qw( ceo )],                       [qw( head_of_dept ceo)],
      [qw( person head_of_dept)],        [qw( person_with_staff head_of_dept )],
      [qw( person3 person_with_staff )], [qw( person4 person_with_staff )],
    );

my %manages;
foreach my $p (values %people) {
    push @{ $manages{ $p->boss } }, $p->name if $p->has_boss;
}

# this part shamelessly stolen from @HunterMcMillen's deleted answer
sub build_tree {
    my ($person) = @_;

    my @subtrees;
    foreach my $managee ( @{ $manages{$person} } ) {
        push @subtrees, build_tree($managee);
    }

    return { $person => \@subtrees };
}

p build_tree 'ceo';

这是输出。

\ {
    ceo   [
        [0] {
            head_of_dept   [
                [0] {
                    person   []
                },
                [1] {
                    person_with_staff   [
                        [0] {
                            person4   []
                        },
                        [1] {
                            person3   []
                        }
                    ]
                }
            ]
        }
    ]
}

这应该或多或少是你想要的。