I'm parsing a raw text file with my parser and a defined template (basically an array) to create a formatted array out of it.
The idea is that each line can have different templates and can be identified with the first characters of the lines. A template means that a line has different values delimited by different lengths/positions.
I have a class, PostionalEdiParser
, with 3 functions:
The parsing functions:
public function parse(array $template = [], array $file = [], $identifierSize=5)
{
if (empty($template)) {
$this->errors["template"] = "No template given";
return $this->errors;
}
// Init array
$my_array = [];
// Init counter
$i = 0;
// SubBody counter
$j = 0;
$previousValue = null;
// Count all lines
$len = count($file);
foreach($file as $row) {
if ($i == 0) { // First Line (header)
$my_array[] = $this->formatLine($template["header"], $row);
$i++;
continue;
} else if ($i == $len-1) { // Last Line (footer)
$my_array[] = $this->formatLine($template["footer"], $row);
$i++;
continue;
}
if(is_array($template["body"])) {
foreach ($template["body"] as $index => $templateSubBody) {
if (substr($row, 0, $identifierSize)==$index) {
$j++;
$my_array[1][$j][]= $this->formatLine($templateSubBody,$row);
continue;
}
if(is_array($templateSubBody)) {
foreach ($templateSubBody as $index2 => $templateSubBody2) {
if(substr($row, 0, $identifierSize)==$index2) {
$my_array[1][$j][] = $this->formatLine($templateSubBody2,$row);
}
}
}
}
$i++;
continue;
}
$i++;
}
return $my_array;
}
Then the formatLine()
function that apply the specific template of the specific line:
public function formatLine($template, $data, $position=0) {
$my_data=[];
foreach($template as $index => $length) {
// add current field to array with the named value
$my_data[$index] = substr($data, $position, $length);
// move the 'pointer' to the start of the next field
$position += $length;
}
return $my_data;
}
And a getter for the errors:
public function errors()
{
return $this->errors;
}
An example of code to understand how it works. This is a defined template and for each key, the value is the length of the fields:
$template = [
"header" => [
"IDENTIFIER"=>2,
"DOT"=>1,
"NUMBER"=>2,
"TEST"=>1,
"HEADER"=>6,
],
"body" => [
"41.00" => [
"IDENTIFIER"=>2,
"DOT"=>1,
"NUMBER"=>2,
"TEST"=>1,
"CONTENT"=>8,
],
"lines" => [
"41.20" => [
"IDENTIFIER"=>2,
"DOT"=>1,
"NUMBER"=>2,
"TEST"=>1,
"CONTENT"=>8,
"SPACE"=>1,
"SUBLINE"=>8
]
]
],
"footer" => [
"IDENTIFIER"=>2,
"DOT"=>1,
"NUMBER"=>2,
"TEST"=>1,
"CONTENT"=>6,
]
];
And this is a file parsed to a rows/lines array:
$rows = [
"00.00 HEADER",
"41.00 CONTENT1",
"41.20 CONTENT2 subline1",
"41.20 CONTENT2 subline2",
"41.00 CONTENT3",
"99.00 FOOTER"
];
By calling this function $resultEdi = $parser->parse($template, $rows);
, I'll get the following result:
array:3 [▼
0 => array:5 [▼ // Header
"IDENTIFIER" => "00"
"DOT" => "."
"NUMBER" => "00"
"TEST" => " "
"HEADER" => "HEADER"
]
1 => array:2 [▼ // Body
1 => array:2 [▼ // Group 1
0 => array:5 [▼ // Group 1 header
"IDENTIFIER" => "41"
"DOT" => "."
"NUMBER" => "00"
"TEST" => " "
"CONTENT" => "CONTENT1"
]
1 => array:7 [▼ // Group 1 line
"IDENTIFIER" => "41"
"DOT" => "."
"NUMBER" => "20"
"TEST" => " "
"CONTENT" => "CONTENT2"
"SPACE" => " "
"SUBLINE" => "subline"
]
]
2 => array:1 [▼ // Group 2
0 => array:5 [▼ // Group 2 header
"IDENTIFIER" => "41"
"DOT" => "."
"NUMBER" => "00"
"TEST" => " "
"CONTENT" => "CONTENT3"
]
]
]
2 => array:5 [▼ // Footer
"IDENTIFIER" => "99"
"DOT" => "."
"NUMBER" => "00"
"TEST" => " "
"CONTENT" => "FOOTER"
]
]
Since it's my first time creating a parser, I have different question for this code:
- As I'm trying to make it easy to customize, would it be better to make the header/footer processing optional?
- What is a proper way to do error handling?
- There is a "sub template" (here it's the lines template) with a 2 dimensional array. Would it be smart to create a recursive function outside of the
parse()
, so that we can have deeper templating possibility?