I am writing a java program in which I have to expand a COBOL copybook if it contains OCCURS clause.
The number next to OCCURS keyword defines repetition of lines child to the OCCURS clause. First number of line defines level. There may be more than one child elements for one OCCURS. Suppose input copybook looks like below:
01 TEST-REC.
05 VAR1 PIC X(02).
05 VAR2 OCCURS 2.
10 VAR3 PIC X(3).
05 VAR6 PIC X(02).
then output should be (ignore first line from input):
05 VAR1 PIC X(02).
10 VAR3 PIC X(3).
10 VAR3 PIC X(3).
05 VAR6 PIC X(02).
I have written following code for handling this and it works fine.
public class Test{
private static String copyBookExpansaion = "";
private static BufferedReader br1 = null;
public static void parseLine() throws IOException{
String line;
while((line = br1.readLine()) != null){
if(line.indexOf(" OCCURS ") == -1){
copyBookExpansaion = copyBookExpansaion + line.trim() + "\n";
}
else{
String s[] = line.trim().replaceAll(" +"," ").split(" ");
int size = Integer.parseInt(s[3].replaceAll("[^0-9]", ""));
line = br1.readLine();
for(int i = 0; i < size;i++){
copyBookExpansaion = copyBookExpansaion + line.trim() + "\n";
}
}
}
return;
}
/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
FileInputStream copyBook= new FileInputStream("C:\\Users\\DadMadhR\\Desktop\\temp\\copybook\\test_Copybook.cpy");
br1 = new BufferedReader(new InputStreamReader(copyBook));
br1.readLine();
parseLine();
System.out.println(copyBookExpansaion);
}
}
I am not able to handle nested OCCURS clause. Suppose my input looks like below:
01 TEST-REC.
05 VAR1 PIC X(02).
05 VAR2 OCCURS 2.
10 VAR3 PIC X(3).
10 VAR4 OCCURS 2.
15 VAR5 PIC X(2).
05 VAR6 PIC X(02).
then output should look like below:
05 VAR1 PIC X(02).
10 VAR3 PIC X(3).
15 VAR5 PIC X(2).
15 VAR5 PIC X(2).
10 VAR3 PIC X(3).
15 VAR5 PIC X(2).
15 VAR5 PIC X(2).
05 VAR6 PIC X(02).
There is no limitation on number of nested OCCURS. I am not getting an approach to handle nested OCCURS.
Can anyone suggest a way to handle this case?
Try this
Step 1. Make tree structure. Each line has a parent. Parent's level (01, 05, ...) is smaller than the line's level. So the structure is
01 TEST-REC.
|
+--05 VAR1 PIC X(02).
|
+--05 VAR2 OCCURS 2.
| |
| +--10 VAR3 PIC X(3).
| |
| +--10 VAR4 OCCURS 2.
| |
| +--15 VAR5 PIC X(2).
|
+--05 VAR6 PIC X(02).
Step 2. Write the structure to stream.
(a) If the line contains PIC
then write self line.
(b) Write each child recursively.
(If the line contains OCCURS N
then repeat N times.)
public class Test {
static class Node {
final int level;
final String line;
final List<Node> children = new ArrayList<>();
Node(int level, String line) {
this.level = level;
this.line = line;
}
void write(PrintStream out) {
int n = 1;
if (line.contains("OCCURS"))
n = Integer.parseInt(line.replaceAll("^.* |[^\\d]*$", ""));
if (line.contains("PIC"))
out.println(line);
for (int i = 0; i < n; ++i)
for (Node child : children)
child.write(out);
}
}
static Node parse(String inputFile) throws IOException {
try (BufferedReader reader = new BufferedReader(
new InputStreamReader(new FileInputStream(inputFile)))) {
List<Node> lines = new ArrayList<>();
String line;
int no = 0;
while ((line = reader.readLine()) != null) {
++no;
line = line.trim();
int level = Integer.parseInt(line.replaceFirst("\\s.*", ""));
Node child = new Node(level, line);
if (lines.size() > 0) {
boolean found = false;
for (int i = lines.size() - 1; i >= 0; --i) {
Node parent = lines.get(i);
if (parent.level < level) {
parent.children.add(child);
found = true;
break;
}
}
if (!found)
throw new RuntimeException(
"parent not found for line " + no + " : " + line);
}
lines.add(child);
}
return lines.get(0);
}
}
public static void main(String[] args) throws IOException {
// Step 1
Node top = parse("C:\\Users\\DadMadhR\\Desktop\\temp\\copybook\\test_Copybook.cpy");
// Step 2
top.write(System.out);
}
}