ФорумПрограммированиеPHP для идиотов → Парсер разметки, для идиотов

Парсер разметки, для идиотов

  • Коля Дубр

    Сообщения: 45 Репутация: N Группа: Адекваты

    Spritz 26 сентября 2012 г. 13:10

    Задача - еще один говнючий шаблонизатор, грубо говоря. Пишем что-то типа:

    {template id="header"}
    <div class="header">
    {template id="header_data"}
    {call id="general_block"}
    {param id="foo"}bar{/param}
    {param id="data"}<div class="data">Smth.</div>{/param}
    {/call}
    {/template}
    </div>
    {/template}


    Зачем это надо - оставим за скобками. Есть такой синтаксис, есть код, который разбивает это на токены (в плоский массив), что-то типа:


    array(
    array('name' => 'template', 'type' => 'open', 'id' => 'header'),
    array('type' => 'string', 'value' => '<div class="header">'),
    array('name' => 'template', 'type' => 'open', 'id' => 'header_data'),
    array('name' => 'call', 'type' => 'open', 'id' => 'general_block'),

    array('name' => 'call', 'type' => 'close'),
    array('name' => 'template', 'type' => 'close')

    )


    Хочется из такого плоского массива построить дерево. Типа такого:

    array(
    'name' => 'template', 'id' => 'header', 'content' => array(
    array('type' => 'string', 'value' => '<div>…</div>'),
    array('name' => 'template', 'id' => 'header_data', 'content' => array(
    array('name' => 'call', 'id' => 'general_block', 'content' => array(



    Как это сделать тупым способом - примерно ясно. А как сделать умным, чтоб по науке? Подскажите алгоритм/паттерн, и чтоб поменьше матана. Статью "Синтаксический анализ" в википедии читал, по ссылкам ходил - сплошной матан, ничего не понял =)

    В качестве усложнения: например, конструкция "call" может иметь вид {call id="smth"}, а может {call id="smth"}{param}…{/param}{/call} - делать для первого случая маркер одиночности {call /} не хочется, надо раздуплить что он одиночный по следующим токенам.
  • phpdude

    Сообщения: 26646 Репутация: N Группа: в ухо

    Spritz 26 сентября 2012 г. 13:39, спустя 28 минут 45 секунд

    хуйта)
    Сапожник без сапог
  • Коля Дубр

    Сообщения: 45 Репутация: N Группа: Адекваты

    Spritz 26 сентября 2012 г. 13:42, спустя 2 минуты 34 секунды

    ты алгоритм напиши, хуйта )
  • phpdude

    Сообщения: 26646 Репутация: N Группа: в ухо

    Spritz 26 сентября 2012 г. 13:57, спустя 15 минут 8 секунд

    ты выбрал путь - написать на пхп xml + xslt transitions.

    хуита - в выборе подхода. вопрос - нахуй это надо? почему не используешь транзишены, если хочется такой синтаксис?
    Сапожник без сапог
  • Коля Дубр

    Сообщения: 45 Репутация: N Группа: Адекваты

    Spritz 26 сентября 2012 г. 14:01, спустя 4 минуты 6 секунд

    Дуд, ну я ж написал:
    Зачем это надо - оставим за скобками.

    Забей на слова "template" и "call", считай что там что-то другое написано. Я бы конечно юзал xslt, если бы была возможность - но задача другая.
    В рамках топика нужно придумать, как из плоского массива с токенами построить дерево.
  • technobulka

    Сообщения: 4540 Репутация: N Группа: Джедаи

    Spritz 26 сентября 2012 г. 15:16, спустя 1 час 15 минут 26 секунд

    array(
    array(
    array( … )
    )
    )

    как же меня бесит эта пехепешная хуйня…
    Высокоуровневое абстрактное говно
  • Коля Дубр

    Сообщения: 45 Репутация: N Группа: Адекваты

    Spritz 26 сентября 2012 г. 15:26, спустя 9 минут 56 секунд

    ясно, профи обосрались =)
  • Frozzeg

    Сообщения: 5641 Репутация: N Группа: Джедаи

    Spritz 26 сентября 2012 г. 15:27, спустя 1 минуту 1 секунду

    где ты видел на пыхе профи :)
    You can be anything you want to be. Just turn yourself into anything you think that you could ever be.
  • technobulka

    Сообщения: 4540 Репутация: N Группа: Джедаи

    Spritz 26 сентября 2012 г. 15:30, спустя 2 минуты 47 секунд

    а че там, что-то спрашивали?
    Высокоуровневое абстрактное говно
  • Коля Дубр

    Сообщения: 45 Репутация: N Группа: Адекваты

    Spritz 26 сентября 2012 г. 16:18, спустя 47 минут 27 секунд

    Можно перечитать первый пост. Но можно и забить, я уже все придумал =)
  • Nyaah

    Сообщения: 574 Репутация: N Группа: Джедаи

    Spritz 26 сентября 2012 г. 16:33, спустя 15 минут

    Простой стек, проверяешь - тег открывающий, если да, то указываешь его как текущий и добавляешь в стек, если тег закрывающий, проверяешь, равен ли тип текущему тегу, если все ок, удаляешь тег из стека, и устанавливаешь текущим тот, что находится в голове стека, если не открывающий и не закрывающий. просто добавляешь его в текущему в конец:
    function normalizeTemplate($data) {
    $stack = array();
    $currentTag = NULL;
    foreach ($data as &$tag) {
    $type = isset($tag['type']) ? $tag['type'] : NULL;
    switch ($type) {
    case 'open':
    if ($currentTag !== NULL) {
    if ($currentTag === false) {
    throw new Exception('Корневой элемент уже имеется');
    }
    addChild($currentTag, $tag);
    }
    $stack[] =& $tag;
    $currentTag =& $tag;
    break;
    case 'close':
    if (empty($currentTag) || $currentTag['name'] !== $tag['name']) {
    throw new Exception('Неверная последовательность закрытия тэгов');
    }
    array_pop($stack);
    $currentTag =& $stack[count($stack) - 1];
    break;
    default:
    addChild($currentTag, $tag);
    break;
    }
    }
    if (!empty($currentTag)) {
    throw new Exception('Имеются незакрытые тэги');
    }
    return $data[0];
    }

    function addChild(&$tag, &$child) {
    if (empty($tag)) {
    throw new Exception('Корневой тег не определён');
    }
    if (!isset($tag['content'])) {
    $tag['content'] = array();
    }
    $tag['content'][] =& $child;
    }

    var_dump(normalizeTemplate(array(
    array('name' => 'template', 'type' => 'open', 'id' => 'header'),
    array('type' => 'string', 'value' => '<div class="header">'),
    array('type' => 'string', 'value' => '<div class="logo"></div>'),
    array('name' => 'template', 'type' => 'open', 'id' => 'header_data'),
    array('name' => 'call', 'type' => 'open', 'id' => 'general_block'),
    array('type' => 'param', 'var' => 'foo', 'value' => 'bar'),
    array('type' => 'param', 'var' => 'data', 'value' => '<div class="data">Smth.</div>'),
    array('name' => 'call', 'type' => 'close'),
    array('type' => 'string', 'value' => 'Some other data'),
    array('name' => 'template', 'type' => 'close'),
    array('name' => 'template', 'type' => 'close'),
    )));
    Work, buy, consume, die
  • Коля Дубр

    Сообщения: 45 Репутация: N Группа: Адекваты

    Spritz 26 сентября 2012 г. 18:03, спустя 1 час 30 минут 14 секунд

    О, спасибо =)
    Собственно, у меня получилось оно же, но вместо таскания массива по ссылке я завел класс с методом add().
    Сейчас пытаюсь разрулить историю с необязательным закрытием тегов - тут надо учитывать семантику, а для этого должны быть какие-то правила. Сижу выдумываю.
  • phpdude

    Сообщения: 26646 Репутация: N Группа: в ухо

    Spritz 26 сентября 2012 г. 18:08, спустя 4 минуты 46 секунд

    о лол :)
    Спустя 13 сек.
    велосипедисты!
    Сапожник без сапог
  • kostyl

    Сообщения: 5210 Репутация: N Группа: Джедаи

    Spritz 26 сентября 2012 г. 19:58, спустя 1 час 50 минут 19 секунд

    Nyaah хуярит всем всё ))

Пожалуйста, авторизуйтесь, чтобы написать комментарий!