# Problem description & analysis

Below is the content of CSV file csv.csv:

1,Company,NULL,False,/company

3,Mission,1,False,/company/mission

5,Client 2,10,False,/references/client2

6,Client 1,10,False,/references/client1

7,Client 4,10,True,/references/client4

8,Client 5,10,True,/references/client5

10,References,NULL,False,/references

The CSV file stores relationships of menus. ParentID is ID of the superior level. Now we are trying to output menu names to console according to the following rules:

1. Output menu names in the order of parent & child. Use an indent to represent the parent-child relationship;

2. Display a menu name or not according to the isHidden value;

3. Sort menus of same level MenuName. Below is the desired result:

.Company

.......Team

....Mission

.References

....Client 1

....Client 2

# Solutions

## Method 1: Through recursion

We write the following script p1.dfx in esProc:

 A B C 1 =file("csv.csv").import@ct() 2 =func(A3,A1.select(ParentID==null),1) 3 func 4 for   A3 >if(B4.isHidden=="False",output(fill(".",B3*3-2)/B4.MenuName)) 5 =A1.select(ParentID==B4.ID).sort(MenuName) 6 >if(C5.len()>0,func(A3,C5,B3+1))

Explanation:

A1   Import the CSV file as a table sequence, and add a new column level whose initial values are an empty set.

A2  Call A3’s subprogram, during which parameters are root nodes and the level number.

A3  Define a subprogram.

B4  Loop through A3, which corresponds to the first parameter in the subprogram.

C4  If value of B4’s isHidden is False, output the result of B3*3-2, in which B3 is the current level number, to the console. The result is the number of dots, which will be followed by B4’s MenuName value.

C5  Get all records of the next level.

C6  If the number of records in C5 is greater than 0, call Ad3’s subprogram where parameters are C5 and the current level number+1.

## Method 2: By traversal

We write the following script p1.dfx in esProc:

 A 1 =file("csv.csv").import@ct().derive([]:level) 2 >A1.switch(ParentID,A1:ID) 3 =A1.nodes@p(ParentID) 4 >A3.run(~.run(if(level==[],level=ParentID.level|MenuName))) 5 =A1.select(isHidden=="False").sort(level).(fill(".",level.len()*3-2)/MenuName) 6 >output(A5.concat@n())

Explanation:

A1  Import the CSV file as a table sequence, and add a new column level whose initial values are an empty set.

A2  Perform a self-join through primary key ID and foreign key ParentID.

A3  Search for every record referenced by foreign key ParentID recursively and return every referencing path between the root node to the current node.

A4  Loop through A3’s sequence and then the current member (a table sequence), during which assign ParentID.level plus MenuName to level if level value is null.

A5  Get records from A1 where isHidden value is False, sort them by level, and join multiple dots with MenuName value into a string according the rules.

A6  Concatenate A5’s strings into a large string by break line and output the result to console.

See How to Call an SPL Script in Java to learn about the integration of an SPL script with a Java program.