0

Some time ago I had to parse nested data attributes to a JSON, so I found a JS solution here on SO. Eg.:

data-title="Title" data-ajax--url="/ajax/url" data-ajax--timeout="10" data-ajax--params--param-1="Param 1"

to

['title' => 'Title', 'ajax' => ['url' => '/ajax/url', 'timeout' => 10, 'params' => ['param-1' => 'Param 1']]]

So now I need a reverse action in PHP. I need to make attributes string from nested array to use it later in HTML. There can be infinite levels.

I've tried recursive functions. Tried recursive iterators. Still no luck. I always lose top level keys and get something like data-ajax--url=[...] --timeout=[...] --param-1=[...] (missing -ajax part) and so on. The part I can't get is the keys - getting values is easy. Any advice would be welcome.

Karmalakas
  • 1,143
  • 2
  • 19
  • 39
  • try http://stackoverflow.com/questions/32286184/access-html-5-data-attribute-in-php – safin chacko Aug 29 '16 at 12:50
  • But that's completely different of what I'm asking. I have an array in PHP and I need to make attributes string like `data-title="Title" data-ajax--url="/ajax/url" data-ajax--timeout="10" data-ajax--params--param-1="Param 1"` :( – Karmalakas Aug 29 '16 at 12:55
  • Can you include a sample nested array in JSON encoded format too. It's easier to simulate with sample data provided instead of trying to create them on our own. – Capital C Aug 29 '16 at 13:03
  • `{"title":"Title","ajax":{"url":"\/ajax\/url","timeout":10,"params":{"param-1":"Param 1"}}}` – Karmalakas Aug 29 '16 at 13:22

2 Answers2

1

This can be achieved with some simple concepts like loop, recursive function and static variable.

Use of static variables is very important here since they remember the last modified value within the function's last call.

Within the loop, we are checking if the currently traversed value is an array.

If it's an array, we are modifying the prefix with the current key and calling the recursive function and .

If not, we are simply concatenating the prefix with the present key.

Try this:

$data = ['title' => 'Title', 'ajax' => ['url' => '/ajax/url', 'timeout' => 10, 'params' => ['param-1' => 'Param 1']]];

function formatter($data = array()) {

    static $prefix      = 'data-';
    static $attr_string = '';
    foreach($data as $key => $value) {
        if (is_array($value)) {
            $prefix  .= $key.'--';
            formatter($value);
        } else {
            $attr_string .= $prefix.$key.'="'.$value.'" ';
        }
    }

    return $attr_string;
}

echo formatter($data);

Output:

data-title="Title" data-ajax--url="/ajax/url" data-ajax--timeout="10" data-ajax--params--param-1="Param 1"
Indrasis Datta
  • 8,692
  • 2
  • 14
  • 32
  • Pretty close, but it fails to remove previously added keys if there are fewer levels in the array than it was in previous cycle. Eg. array `[ 'ajax' => [ 'url' => '/ajax/url', 'test' => 'TEST' ], 'test' => [ 'subtest' => [ 'subsubtest1' => 'Subsubtest1', 'subsubtest2' => 'Subsubtest2' ], 'subtest2' => 'Subtest2' ], 'test-2' => 'Test 2', ]` As You can see, `ajax` is always set in output. I'm using this function as a class method. – Karmalakas Aug 29 '16 at 13:14
0

So after almost 6 hours of trying to figure this out and lots of searches, also with some hints from Object Manipulator, I found this answer on SO and just had to adapt it to my needs:

function makeDataAttributes(array $attributes)
{
    $rs = '';
    $iterator = new \RecursiveIteratorIterator(new \RecursiveArrayIterator($attributes));
    foreach ($iterator as $key => $value) {
        for ($i = $iterator->getDepth() - 1; $i >= 0; $i--) {
            $key = $iterator->getSubIterator($i)->key() . '--' . $key;
        }

        $rs .= ' data-' . $key . '="' . $iterator->current() . '"';
    }

    return trim($rs);
}

Thanks everyone for your comments. It helped me to define my search more clearly. Also got some new knowledge about iterators.

Community
  • 1
  • 1
Karmalakas
  • 1,143
  • 2
  • 19
  • 39