这几天我一直在困惑这个问题,没有运气。我希望你们中的一些人能提供帮助。 从我的数据库中我得到一个文件列表,其中附有各种信息,包括虚拟路径。一些典型的数据是:
Array
(
[0] => Array
(
[name] => guide_to_printing.txt
[virtual_path] => guides/it
)
[1] => Array
(
[name] => guide_to_vpn.txt
[virtual_path] => guides/it
)
[2] => Array
(
[name] => for_new_employees.txt
[virtual_path] => guides
)
)
我希望将它转换为虚拟路径的分层数组结构,因此上面的输出应为:
Array
(
[0] => Array
(
[type] => dir
[name] => guides
[children] => Array
(
[0] => Array
(
[type] => dir
[name] => it
[children] = Array
(
[0] => Array
(
[type] => file
[name] => guide_to_printing.txt
)
[1] => Array
(
[type] => file
[name] => guide_to_vpn.txt
)
)
)
[1] => Array
(
[type] => file
[name] => for_new_employees.txt
)
)
)
)
type属性指示它是目录还是文件。
有人可以帮助创建执行此转换的函数。这将是非常有帮助的。感谢。
到目前为止,我自己的最佳解决方案是:
foreach($docs as $doc) {
$path = explode("/",$doc['virtual_path']);
$arrayToInsert = array(
'name' => $doc['name'],
'path' => $doc['virtual_path'],
);
if(count($path)==1) { $r[$path[0]][] = $arrayToInsert; }
if(count($path)==2) { $r[$path[0]][$path[1]][] = $arrayToInsert; }
if(count($path)==3) { $r[$path[0]][$path[1]][$path[2]][] = $arrayToInsert; }
}
当然这只适用于目录结构中的深度为3,而键是目录名称。
答案 0 :(得分:1)
function hierarchify(array $files) {
/* prepare root node */
$root = new stdClass;
$root->children = array();
/* file iteration */
foreach ($files as $file) {
/* argument validation */
switch (true) {
case !isset($file['name'], $file['virtual_path']):
case !is_string($name = $file['name']):
case !is_string($virtual_path = $file['virtual_path']):
throw new InvalidArgumentException('invalid array structure detected.');
case strpos($virtual_path, '/') === 0:
throw new InvalidArgumentException('absolute path is not allowed.');
}
/* virtual url normalization */
$parts = array();
$segments = explode('/', preg_replace('@/++@', '/', $virtual_path));
foreach ($segments as $segment) {
if ($segment === '.') {
continue;
}
if (null === $tail = array_pop($parts)) {
$parts[] = $segment;
} elseif ($segment === '..') {
if ($tail === '..') {
$parts[] = $tail;
}
if ($tail === '..' or $tail === '') {
$parts[] = $segment;
}
} else {
$parts[] = $tail;
$parts[] = $segment;
}
}
if ('' !== $tail = array_pop($parts)) {
// skip empty
$parts[] = $tail;
}
if (reset($parts) === '..') {
// invalid upper traversal
throw new InvalidArgumentException('invalid upper traversal detected.');
}
$currents = &$root->children;
/* hierarchy iteration */
foreach ($parts as $part) {
while (true) {
foreach ($currents as $current) {
if ($current->type === 'dir' and $current->name === $part) {
// directory already exists!
$currents = &$current->children;
break 2;
}
}
// create new directory...
$currents[] = $new = new stdClass;
$new->type = 'dir';
$new->name = $part;
$new->children = array();
$currents = &$new->children;
break;
}
}
// create new file...
$currents[] = $new = new stdClass;
$new->type = 'file';
$new->name = $name;
}
/* convert into array completely */
return json_decode(json_encode($root->children), true);
}
$files = array(
0 => array (
'name' => 'b.txt',
'virtual_path' => 'A/B//',
),
1 => array(
'name' => 'a.txt',
'virtual_path' => '././A/B/C/../..',
),
2 => array(
'name' => 'c.txt',
'virtual_path' => './A/../A/B/C//////',
),
3 => array(
'name' => 'root.txt',
'virtual_path' => '',
),
);
var_dump(hierarchify($files));
将输出......
array(2) {
[0]=>
array(3) {
["type"]=>
string(3) "dir"
["name"]=>
string(1) "A"
["children"]=>
array(2) {
[0]=>
array(3) {
["type"]=>
string(3) "dir"
["name"]=>
string(1) "B"
["children"]=>
array(2) {
[0]=>
array(2) {
["type"]=>
string(4) "file"
["name"]=>
string(5) "b.txt"
}
[1]=>
array(3) {
["type"]=>
string(3) "dir"
["name"]=>
string(1) "C"
["children"]=>
array(1) {
[0]=>
array(2) {
["type"]=>
string(4) "file"
["name"]=>
string(5) "c.txt"
}
}
}
}
}
[1]=>
array(2) {
["type"]=>
string(4) "file"
["name"]=>
string(5) "a.txt"
}
}
}
[1]=>
array(2) {
["type"]=>
string(4) "file"
["name"]=>
string(8) "root.txt"
}
}
$files = array(
0 => array (
'name' => 'invalid.txt',
'virtual_path' => '/A/B/C',
),
);
var_dump(hierarchify($files));
会抛出......
Fatal error: Uncaught exception 'InvalidArgumentException' with message 'absolute path is not allowed.'
$files = array(
0 => array (
'name' => 'invalid.txt',
'virtual_path' => 'A/B/C/../../../../../../../..',
),
);
var_dump(hierarchify($files));
会抛出......
Fatal error: Uncaught exception 'InvalidArgumentException' with message 'invalid upper traversal detected.'
答案 1 :(得分:0)
有这样的事情:
foreach ($array as $k => $v) {
$tmp = explode('/',$v['virtual_path']);
if(sizeof($tmp) > 1){
$array_result[$tmp[0]]['children'][$k]['type'] = 'file';
$array_result[$tmp[0]]['children'][$k]['name'] = $v['name'];
$array_result[$tmp[0]]['type'] = 'dir';
$array_result[$tmp[0]]['name'] = $v['name'];
}
}
我得到了这样的数组:
Array
(
[guides] => Array
(
[children] => Array
(
[0] => Array
(
[type] => file
[name] => guide_to_printing.txt
)
[1] => Array
(
[type] => file
[name] => guide_to_vpn.txt
)
)
[type] => dir
[name] => guide_to_vpn.txt
)
)
我知道这不是你想要的,但我认为这可以让你朝着正确的方向前进。
答案 2 :(得分:0)
事件虽然你在发布之前应该尝试过一些东西,但我喜欢你的问题并认为这是一个有趣的问题。所以,你去吧
function &createVirtualDirectory(&$structure, $path) {
$key_parts = $path ? explode('/', $path) : null;
$last_key = &$structure;
if (is_array($key_parts) && !empty($key_parts)) {
foreach ($key_parts as $name) {
// maybe directory exists?
$index = null;
if (is_array($last_key) && !empty($last_key)) {
foreach ($last_key as $key => $item) {
if ($item['type'] == 'dir' && $item['name'] == $name) {
$index = $key;
break;
}
}
}
// if directory not exists - create one
if (is_null($index)) {
$last_key[] = array(
'type' => 'dir',
'name' => $name,
'children' => array(),
);
$index = count($last_key)-1;
}
$last_key =& $last_key[$index]['children'];
}
}
return $last_key;
}
$input = array(
0 => array (
'name' => 'guide_to_printing.txt',
'virtual_path' => 'guides/it',
),
1 => array(
'name' => 'guide_to_vpn.txt',
'virtual_path' => 'guides/it',
),
2 => array(
'name' => 'for_new_employees.txt',
'virtual_path' => 'guides',
)
);
$output = array();
foreach ($input as $file) {
$dir =& createVirtualDirectory($output, $file['virtual_path']);
$dir[] = array(
'type' => 'file',
'name' => $file['name']
);
unset($dir);
}
print_r($output);
提供您想要的确切输出
答案 3 :(得分:0)
这是使用2个递归函数执行此操作的简单方法。 一个解析一行数据的函数。 另一个合并每个解析的数据行。
// Assuming your data are in $data
$tree = array();
foreach ($data as $item) {
$tree = merge($tree, parse($item['name'], $item['virtual_path']));
}
print json_encode($tree);
// Simple parser to extract data
function parse($name, $path){
$parts = explode('/', $path);
$level = array(
'type' => 'dir',
'name' => $parts[0],
'children' => array()
);
if(count($parts) > 1){
$path = str_replace($parts[0] . '/', '', $path);
$level['children'][] = parse($name, $path);
}
else {
$level['children'][] = array(
'type' => 'file',
'name' => $name
);
}
return $level;
}
// Merge a new item to the current tree
function merge($tree, $new_item){
if(!$tree){
$tree[] = $new_item;
return $tree;
}
$found = false;
foreach($tree as $key => &$item) {
if($item['type'] === $new_item['type'] && $item['name'] === $new_item['name']){
$item['children'] = merge($item['children'], $new_item['children'][0]);
$found = true;
break;
}
}
if(!$found) {
$tree[] = $new_item;
}
return $tree;
}