Skip to content

Instantly share code, notes, and snippets.

@AGelzer
Last active May 4, 2025 10:18
Show Gist options
  • Save AGelzer/8cbc480e2094cbe14ff59dee330d4de1 to your computer and use it in GitHub Desktop.
Save AGelzer/8cbc480e2094cbe14ff59dee330d4de1 to your computer and use it in GitHub Desktop.
<?php
/**
* Convert Path String to Tree
* see https://www.gnu.org/software/bash/manual/html_node/Brace-Expansion.html
*
*/
function convertPathsStringToTree(string $dataPathsString): array
{
$tree = [];
$stack = [&$tree];
$exitStackFrames = [0];
$dataPathsString = str_replace(' ', '',$dataPathsString);
$tokens = preg_split('~(/|[,{}])~', $dataPathsString, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
if ($errors = validatePathsTokens($tokens)) {
throw new Exception('Invalid data paths format: '. implode(', ', $errors));
}
foreach ($tokens as $token) {
$current = &$stack[array_key_last($stack)];
switch ($token) {
case '/':
$current['children'] = [];
$stack[] = &$current['children'];
break;
case '{':
$exitStackFrames[] = array_key_last($stack);
break;
case '}':
array_pop($exitStackFrames);
break;
case ',':
$exitStackFrame = $exitStackFrames[array_key_last($exitStackFrames)];
$stack = array_slice($stack, 0, $exitStackFrame + 1, true);
break;
default:
$current[$token] = ['propertyName' => $token];
$stack[] = &$current[$token];
break;
}
}
return $tree;
}
function validatePathsTokens(array $tokens): array
{
$errors = [];
foreach ($tokens as $token) {
$tokenType = in_array($token, ['/', '{','}',',']) ? $token : 'propertyName';
if (isset($prevTokenType)) {
if ($tokenType !== ',' && $prevTokenType === '}') {
$errors[] = 'A closing brace } must be followed by a comma or be at the end.';
}
if ($tokenType === ',' && $prevTokenType !== '/' && $prevTokenType !== '}') {
$errors[] = 'Syntax Error: A comma is allowed only after an element or a closing brace }';
}
if ($tokenType === '/' && $prevTokenType !== 'propertyName') {
$errors[] = 'Syntax Error: The / operator must be preceded by an element.';
}
if ($tokenType === '{' && $prevTokenType !== '/') {
$errors[] = 'Syntax Error: An opening brace { must be preceded by /.';
}
} elseif ($tokenType !== 'propertyName') {
$errors[] = 'Syntax Error: The first element in the data paths string must be a propertyName.';
}
$prevTokenType = $tokenType;
}
return $errors;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment