lithium\util\Set::extract PHP Method

extract() public static method

Implements partial support for XPath 2.0.
public static extract ( array $data, string $path = null, array $options = [] ) : array
$data array An array of data to extract from.
$path string An absolute XPath 2.0 path. Only absolute paths starting with a single slash are supported right now. Implemented selectors: - `'/User/id'`: Similar to the classic {n}.User.id. - `'/User[2]/name'`: Selects the name of the second User. - `'/User[id>2]'`: Selects all Users with an id > 2. - `'/User[id>2][<5]'`: Selects all Users with an id > 2 but < 5. - `'/Post/Comment[author_name=John]/../name'`: Selects the name of all posts that have at least one comment written by John. - `'/Posts[name]'`: Selects all Posts that have a `'name'` key. - `'/Comment/.[1]'`: Selects the contents of the first comment. - `'/Comment/.[:last]'`: Selects the last comment. - `'/Comment/.[:first]'`: Selects the first comment. - `'/Comment[text=/lithium/i]`': Selects the all comments that have a text matching the regex `/lithium/i`. - `'/Comment/@*'`: Selects all key names of all comments.
$options array Currently only supports `'flatten'` which can be disabled for higher XPath-ness.
return array An array of matched items.
    public static function extract(array $data, $path = null, array $options = array())
    {
        $defaults = array('flatten' => true);
        $options += $defaults;
        if (!$data) {
            return array();
        }
        if ($path === '/') {
            return array_filter($data, function ($data) {
                return $data === 0 || $data === '0' || !empty($data);
            });
        }
        $contexts = $data;
        if (!isset($contexts[0])) {
            $contexts = array($data);
        }
        $tokens = array_slice(preg_split('/(?<!=)\\/(?![a-z-]*\\])/', $path), 1);
        do {
            $token = array_shift($tokens);
            $conditions = false;
            if (preg_match_all('/\\[([^=]+=\\/[^\\/]+\\/|[^\\]]+)\\]/', $token, $m)) {
                $conditions = $m[1];
                $token = substr($token, 0, strpos($token, '['));
            }
            $matches = array();
            foreach ($contexts as $key => $context) {
                if (!isset($context['trace'])) {
                    $context = array('trace' => array(null), 'item' => $context, 'key' => $key);
                }
                if ($token === '..') {
                    if (count($context['trace']) === 1) {
                        $context['trace'][] = $context['key'];
                    }
                    array_pop($context['trace']);
                    $parent = join('/', $context['trace']);
                    $context['item'] = static::extract($data, $parent);
                    array_pop($context['trace']);
                    $context['item'] = array_shift($context['item']);
                    $matches[] = $context;
                    continue;
                }
                $match = false;
                if ($token === '@*' && is_array($context['item'])) {
                    $matches[] = array('trace' => array_merge($context['trace'], (array) $key), 'key' => $key, 'item' => array_keys($context['item']));
                } elseif (is_array($context['item']) && isset($context['item'][$token])) {
                    $items = $context['item'][$token];
                    if (!is_array($items)) {
                        $items = array($items);
                    } elseif (!isset($items[0])) {
                        $current = current($items);
                        if (is_array($current) && count($items) <= 1 || !is_array($current)) {
                            $items = array($items);
                        }
                    }
                    foreach ($items as $key => $item) {
                        $ctext = array($context['key']);
                        if (!is_numeric($key)) {
                            $ctext[] = $token;
                            $token = array_shift($tokens);
                            if (isset($items[$token])) {
                                $ctext[] = $token;
                                $item = $items[$token];
                                $matches[] = array('trace' => array_merge($context['trace'], $ctext), 'key' => $key, 'item' => $item);
                                break;
                            } else {
                                array_unshift($tokens, $token);
                            }
                        } else {
                            $ctext[] = $token;
                        }
                        $matches[] = array('trace' => array_merge($context['trace'], $ctext), 'key' => $key, 'item' => $item);
                    }
                } elseif ($key === $token || is_numeric($token) && $key == $token || $token === '.') {
                    $context['trace'][] = $key;
                    $matches[] = array('trace' => $context['trace'], 'key' => $key, 'item' => $context['item']);
                }
            }
            if ($conditions) {
                foreach ($conditions as $condition) {
                    $filtered = array();
                    $length = count($matches);
                    foreach ($matches as $i => $match) {
                        if (static::matches($match['item'], array($condition), $i + 1, $length)) {
                            $filtered[] = $match;
                        }
                    }
                    $matches = $filtered;
                }
            }
            $contexts = $matches;
            if (empty($tokens)) {
                break;
            }
        } while (true);
        $r = array();
        foreach ($matches as $match) {
            $key = array_pop($match['trace']);
            $condition = !is_int($key) && $key !== null;
            if ((!$options['flatten'] || is_array($match['item'])) && $condition) {
                $r[] = array($key => $match['item']);
            } else {
                $r[] = $match['item'];
            }
        }
        return $r;
    }

Usage Example

Beispiel #1
0
 /**
  * returns rendered content
  *
  * @param string $content input content
  * @param string $data field to retrieve from configuration
  * @param array $options an array with additional options
  * @return string content as given
  * @filter
  */
 public function get($content, $data = null, array $options = array())
 {
     $defaults = array('default' => array(), 'flat' => false);
     $options += $defaults;
     $params = compact('content', 'data', 'options');
     return $this->_filter(__METHOD__, $params, function ($self, $params) {
         extract($params);
         try {
             $config = NeonFormatter::decode($content);
         } catch (NeonException $e) {
             return $options['default'];
         } catch (Exception $e) {
             return $options['default'];
         }
         if (!empty($data) && is_scalar($data)) {
             if (array_key_exists($data, (array) $config)) {
                 return $config[$data];
             }
         }
         if ($data) {
             $data = '/' . str_replace('.', '/', $data) . '/.';
             $result = current(Set::extract((array) $config, $data));
             return !empty($result) ? $result : null;
         }
         return $options['flat'] ? Set::flatten($config) : $config;
     });
 }
All Usage Examples Of lithium\util\Set::extract