Инструменты пользователя

Инструменты сайта


wiki:devel:parser

Различия

Показаны различия между двумя версиями страницы.

Ссылка на это сравнение

Предыдущая версия справа и слеваПредыдущая версия
Следующая версия
Предыдущая версия
wiki:devel:parser [2025/01/16 20:53] – [Handler (Обработчик)] vladpolskiywiki:devel:parser [2025/01/17 13:53] (текущий) – [Преобразователь] vladpolskiy
Строка 246: Строка 246:
  
 <diagram> <diagram>
-AbstractRewriter.php|| +|AAA||AAA{text-align:left;border-color:white}={{fa>folder?}} Handler 
-|)|{{fa>file?}} Block.php| +|)|BBB|BBB{text-align:left;border-color:white}={{fa>file?}} AbstractRewriter.php 
-|)| CCC|CCC{text-align:left;border-color:white}=Lists.php +|)|CCC|CCC{text-align:left;border-color:white}={{fa>file?}} Block.php 
-|)| Nest.php| +|)|DDD|DDD{text-align:left;border-color:white}={{fa>file?}} CallWriter.php 
-|)| ReWriterInterface.php| +|)|EEE|EEE{text-align:left;border-color:white}={{fa>file?}} Nest.php 
-|)| Table.php| +|)|FFF|FFF{text-align:left;border-color:white}={{fa>file?}} Lists.php 
-|)| CallWriter.php| +|)|GGG|GGG{text-align:left;border-color:white}={{fa>file?}} CallWriterInterface.php 
-|)| CallWriterInterface.php| +|)|KKK|KKK{text-align:left;border-color:white}={{fa>file?}} Preformatted.php 
-|)| Preformatted.php| +|)|LLL|LLL{text-align:left;border-color:white}={{fa>file?}} Quote.php 
-|`| Quote.php|+|)|MMM|MMM{text-align:left;border-color:white}={{fa>file?}} ReWriterInterface.php 
 +|`|NNN|NNN{text-align:left;border-color:white}={{fa>file?}} Table.php
 </diagram> </diagram>
  
 +Handler — это класс, предоставляющий методы, которые вызывает Lexer, когда он сопоставляет токены. Затем он «тонко настраивает» токены в последовательность инструкций, готовых для Renderer.
  
-Обработчик --- это класс, реализующий методы, которые вызываются лексическим анализатором, когда тот обнаруживает вхождения. Затем он «тонко преобразует» вхождения в последовательность инструкций, готовых для передачи преобразователю.+Обработчик в целом содержит следующие классы:
  
-Обработчик как целое состоит из следующих классов:+  * [[wiki:devel:parser:doku_handler|Doku_Handler]]: все вызовы из Lexer производятся в этот класс. Для каждого режима, зарегистрированного в Lexer, будет соответствующий метод в Handler
  
-  * ''Doku_Handler'': все вызовы из анализатора адресованы этому классуДля каждого режима, зарегистрированного анализатором, будет соответствующий ему метод в обработчике+''Doku_Handler'' в [[xref>inc:extension:syntaxplugin.php|/dokuwiki/inc/Extension/SyntaxPlugin.php]] 
-  * ''Doku_Handler_CallWriter'': реализует «прокладку» между массивом инструкций (массив ''Doku_Handler::$calls'') и методами обработчика, //записывающими// эти инструкцииПока идёт лексический анализ, он будет временно перемещён другими объектами, вроде ''Doku_Handler_List''+<code php SyntaxPlugin.php > 
-  * ''Doku_Handler_List'': отвечает за трансформацию перечня вхождений в инструкции, пока идёт лексический разбор. + 6  use Doku_Handler; 
-  * ''Doku_Handler_Preformatted'': отвечает за трансформацию предварительно отформатированных вхождений (врезки в «Докувики»в инструкции, пока идёт лексический разбор. +57  @see Doku_Handler_Block 
-  ''Doku_Handler_Quote'': отвечает за трансформацию вхождений цитат (текста, начинающего с одной или более «>») в инструкции, пока идёт лексический разбор+75  * @param Doku_Handler $handler The Doku_Handler object 
-  * ''Doku_Handler_Table'': отвечает за трансформацию вхождений таблиц в инструкции, пока идёт лексический разбор+77  * @param   Doku_Handler $handler The Doku_Handler object 
-  ''Doku_Handler_Section'': отвечает за вставку инстукций секций, основываясь на позиции инструкций заголовков, только когда лексический анализ завершён --- повторяется однократно+80  abstract public function handle($match, $state, $pos, Doku_Handler $handler); 
-  * ''Doku_Handler_Block'': отвечает за вставку инструкций 'p_open' и 'p_close', будучи осведомлённым об инструкциях 'block level' instructions, только когда лексический анализ завершён (т. е. он повторяется однократно посредством, выдавая полный перечень инструкций и вставляет дополнитльеный инструкции). +</code> 
-  * ''Doku_Handler_Toc'': отвечает за добавление инструкций таблицы содержания в начало последовательности, основываясь на инструкциях заголовка, только когда лексический анализ завершён (т. е. он повторяется однократно посредством, выдавая полный перечень инструкций и вставляет дополнитльеный инструкции).+''Doku_Handler'' в [[xref>inc:parsing:parser.php|/dokuwiki/inc/Parsing/Parser.php]] 
 +<code php Parser.php > 
 +6 use Doku_Handler; 
 +17  /** @var Doku_Handler */ 
 +32  @param Doku_Handler $handler 
 +34  public function __construct(Doku_Handler $handler
 +</code> 
 +''Doku_Handler'' в [[xref>inc:parser:handler.php|/dokuwiki/inc/parser/handler.php]] 
 +<code php handler.php > 
 +16   Class Doku_Handler 
 +18   class Doku_Handler { 
 +40   * Doku_Handler constructor
 +795  $link[1] = Doku_Handler_Parse_Media($link[1]); 
 +878  $p = Doku_Handler_Parse_Media($match)
 +1023 function Doku_Handler_Parse_Media($match) { 
 +</code>
  
-=== Методы вхождений обработчика ===+  * [[xref>inc:parsing:handler:callwriter.php|CallWriter]]: обеспечивает слой между массивом инструкций (массив ''Doku_Handler::$calls'' и методами Handler, //записывающими// эти инструкции. Пока идёт лексический анализ, он будет временно перемещён другими объектами, вроде ''dokuwiki\Parsing\Handler\List''
 +  * [[xref>inc:parsing:handler:lists.php|List]]: отвечает за преобразование токенов списка в инструкции, пока выполняется лексический анализ 
 +  * [[xref>inc:parsing:handler:quote.php|Quote]]: отвечает за преобразование токенов ''blockquote'' (текст, начинающийся с одного или нескольких >) в инструкции, пока выполняется лексический анализ 
 +  * [[xref>inc:parsing:handler:table.php|Table]]: отвечает за преобразование токенов таблицы в инструкции, пока выполняется лексический анализ 
 +  * [[xref>inc:parsing:handler:block.php|Block]]: отвечает за вставку инструкций «p_open» и «p_close», при этом отслеживая инструкции «уровня блока», после завершения всего лексического анализа (т.е. выполняет цикл один раз по всему списку инструкций и вставляет больше инструкций) 
 +  * [[xref>inc:parsing:handler:abstractrewriter.php|AbstractRewriter]]: расширено Preformattedи Nest… FIXME 
 +  * [[xref>inc:parsing:handler:nest.php|Nest]]: ...FIXME 
 +  * [[xref>inc:parsing:handler:preformatted.php|Preformatted]]: отвечает за преобразование предварительно отформатированных токенов (отступ в тексте dokuwiki) в инструкции, пока лексический анализ еще выполняется
  
-Обработчик должен реализовывать методы, соответствующие режимам, зарегистрированным анализатором (подразумевается метод ''%%mapHandler()%%'' анализатора --- см. выше).+=== Методы токенов обработчиков ===
  
-Напримересли вы зарегистировали в анализаторе режим ''file'' наподобие:+Обработчик должен предоставлять методы, названные в соответствии с режимами, зарегистрированными в лексическом анализаторе (имея в виду %%mapHandler()%% метод лексического анализатора — см. выше). 
 + 
 +Например, если вы зарегистрировали режим файла с помощью Lexer, например:
  
 <code php> <code php>
-$Lexer->addEntryPattern('<file>(?=.*</file>)','base','file'); +$lexer->addEntryPattern('<file>(?=.*</file>)','base','file'); 
-$Lexer->addExitPattern('</file>','file');+$lexer->addExitPattern('</file>','file');
 </code> </code>
  
-Обработчику требуется метод вроде:+Обработчику понадобится такой метод:
  
 <code php> <code php>
 class Doku_Handler { class Doku_Handler {
 + 
     /**     /**
-    * @строковый параметр match содержит текст, который был обнаружен +    * @param string match содержит совпавший текст 
-    * @целочисленный параметр state - тип совпадения (см. ниже) +    * @param int state - тип найденного соответствия (см. ниже) 
-    * @целочисленный параметр pos - индекс байта, где было найдено совпадение+    * @param int pos - индекс байта, где было найдено совпадение
     */     */
-    function file($match, $state, $pos) { +    public function file($match, $state, $pos) { 
-        return TRUE;+        return true;
     }     }
 } }
 </code> </code>
  
-**Замечание:** метод обработчика //обязан// вернуть «TRUE» или анализатор будет немедленно остановленПодобное поведение может быть полезным, когда встречаются другие проблемы обработки, но в парсере «Докувики» все методы обработчика //всегда// возвращают «TRUE».+**Примечание:** метод Handler //должен// возвращать **true**, иначе Lexer немедленно остановитсяТакое поведение может быть полезным при работе с другими типами проблем синтаксического анализа, но для парсера DokuWiki все методы Handler //всегда// будут возвращать **true**.
  
 Аргументы, реализумые методом обработчика; Аргументы, реализумые методом обработчика;
Строка 423: Строка 449:
 В случае со списками, это требует помощи класса ''Doku_Handler_List'', который принимает вхождения, заменяя их на корректные инструкции для Преобразователя. В случае со списками, это требует помощи класса ''Doku_Handler_List'', который принимает вхождения, заменяя их на корректные инструкции для Преобразователя.
  
-==== Парсер ====+==== Parser (Парсер====
  
-Парсер играет роль переднего рубежа для внешнего кода и устанавливает для лексического анализатора паттерны и режимы, описывающие синтаксис «Докувики».+Определено в [[xref>inc:parsing:parser.php|/dokuwiki/inc/Parsing/Parser.php]] и [[xref>inc:parser:parser.php|/dokuwiki/inc/parser/parser.php]].
  
-Использование парсера в общем случае выглядит следущим образом:+dokuwiki [[xref>inc:parsing:parser.php|\Parsing\Parser]] действует как интерфейс для внешнего кода и настраивает Lexer с помощью шаблонов и режимов, описывающих синтаксис DokuWiki. 
 + 
 +Использование парсера обычно выглядит так:
  
 <code php> <code php>
-// Создать парсер +// Создаем обработчик Handler 
-$Parser new Doku_Parser();+$handler = new Doku_Handler();
  
-// Создать обработчик и поместить в парсер +// Создаем парсер с обработчиком  
-$Parser->Handler new Doku_Handler();+$parser = new dokuwiki\Parsing\Parser($handler);
  
-// Добавить требуемые синтаксические режимы в парсер +// Добавить требуемые режимы синтаксиса в парсер  
-$Parser->addMode('footnote',new Doku_Parser_Mode_Footnote()); +$parser->addMode('footnote', new dokuwiki\Parsing\ParserMode\Footnote()); 
-$Parser->addMode('hr',new Doku_Parser_Mode_HR()); +$parser->addMode('hr', new dokuwiki\Parsing\ParserMode\Hr()); 
-$Parser->addMode('unformatted',new Doku_Parser_Mode_Unformatted());+$parser->addMode('unformatted', new dokuwiki\Parsing\ParserMode\Unformatted());
 # etc. # etc.
  
 $doc = file_get_contents('wikipage.txt.'); $doc = file_get_contents('wikipage.txt.');
-$instructions = $Parser->parse($doc);+$instructions = $parser->parse($doc);
 </code> </code>
  
 Более подробные примеры приведены ниже. Более подробные примеры приведены ниже.
  
-В целом, парсер также содержит классы, предсталяющие по отдельности каждый из доступных режимов, базовым классом для всех них является ''Doku_Parser_Mode''. Поведение этих режимов лучше всего понять, посмотрев на примеры добавления синтаксиса ниже в этом документе.+В целом Parser также содержит классы, представляющие каждый доступный режим синтаксиса, базовым классом для всех них является [[xref>inc:parsing:parsermode:abstractmode.php|dokuwiki\Parsing\ParserMode\AbstractMode]]. Поведение этих режимов лучше всего понять, рассмотрев примеры добавления синтаксиса далее в этом документе.
  
-//Причиной// для представления режимов как классов является желание избежать повторяющихся вызовов методов анализатора. Без них было бы необходимо упорно разрабатывать каждое правило паттерна для каждого режима, в котором паттерн мог бы сравниваться, например, для регистрации единого правила паттерна для синтаксиса ссылок ВерблюжьегоСтиля (CamelCase) требовалось бы что-то вроде:+Причина представления режимов с помощью классов заключается в том, чтобы избежать повторных вызовов методов Lexer. Без них пришлось бы жестко кодировать каждое правило шаблона для каждого режима, в котором может быть сопоставлен шаблон, например, регистрация одного правила шаблона для синтаксиса ссылок CamelCase потребовала бы чего-то вроде:
  
 <code php> <code php>
-$Lexer->addSpecialPattern('\b[A-Z]+[a-z]+[A-Z][A-Za-z]*\b','base','camelcaselink'); +$lexer->addSpecialPattern('\b[A-Z]+[a-z]+[A-Z][A-Za-z]*\b', 'base', 'camelcaselink'); 
-$Lexer->addSpecialPattern('\b[A-Z]+[a-z]+[A-Z][A-Za-z]*\b','footnote','camelcaselink'); +$lexer->addSpecialPattern('\b[A-Z]+[a-z]+[A-Z][A-Za-z]*\b', 'footnote', 'camelcaselink'); 
-$Lexer->addSpecialPattern('\b[A-Z]+[a-z]+[A-Z][A-Za-z]*\b','table','camelcaselink'); +$lexer->addSpecialPattern('\b[A-Z]+[a-z]+[A-Z][A-Za-z]*\b', 'table', 'camelcaselink'); 
-$Lexer->addSpecialPattern('\b[A-Z]+[a-z]+[A-Z][A-Za-z]*\b','listblock','camelcaselink'); +$lexer->addSpecialPattern('\b[A-Z]+[a-z]+[A-Z][A-Za-z]*\b', 'listblock', 'camelcaselink'); 
-$Lexer->addSpecialPattern('\b[A-Z]+[a-z]+[A-Z][A-Za-z]*\b','strong','camelcaselink'); +$lexer->addSpecialPattern('\b[A-Z]+[a-z]+[A-Z][A-Za-z]*\b', 'strong', 'camelcaselink'); 
-$Lexer->addSpecialPattern('\b[A-Z]+[a-z]+[A-Z][A-Za-z]*\b','underline','camelcaselink'); +$lexer->addSpecialPattern('\b[A-Z]+[a-z]+[A-Z][A-Za-z]*\b', 'underline', 'camelcaselink'); 
-// etc.+// и т.д.
 </code> </code>
  
-Каждый режим, который позволяет содержать ссылки ВерблюжьегоСтиля должен был быть явно указан.+Каждый режим, которому разрешено содержать ссылки CamelCase, должен быть явно назван.
  
-Вместо этого используется единый класс вроде:+Вместо того, чтобы жестко кодировать это, вместо этого это реализовано с использованием одного класса, например:
  
 <code php> <code php>
-class Doku_Parser_Mode_CamelCaseLink extends Doku_Parser_Mode +namespace dokuwiki\Parsing\ParserMode; 
-     + 
-    function connectTo($mode) {+class CamelCaseLink extends AbstractMode 
 + 
 +    public function connectTo($mode) {
         $this->Lexer->addSpecialPattern(         $this->Lexer->addSpecialPattern(
-                '\b[A-Z]+[a-z]+[A-Z][A-Za-z]*\b',$mode,'camelcaselink' +            '\b[A-Z]+[a-z]+[A-Z][A-Za-z]*\b', $mode, 'camelcaselink' 
-            );+        );
     }     }
-     
 } }
 </code> </code>
  
-При установке параметров лексического анализаторапарсер вызывает метод ''%%connectTo%%'' объекта ''Doku_Parser_Mode_CamelCaseLink'' для любого режима, который принимает синтаксис ВерблюжьегоСтиля.+При настройке лексического анализатора парсер вызывает ''%%connectTo()%%'' метод объекта ''dokuwiki\Parsing\ParserMode\CamelCaseLink'' для каждого другого режима, который принимает синтаксис CamelCase (некоторым такой ''%%<code />%%'' синтаксис не нравится). 
 + 
 +За счет усложнения понимания настройки лексического анализатора это позволяет сделать код более гибким при добавлении нового синтаксиса. 
  
-Это позволяет коду быть более гибким при добавлении новых синтаксических конструкций. 
  
 ==== Формат данных инструкций ==== ==== Формат данных инструкций ====
  
-Следующее показывает пример исходного текста вики и соответствующий вывод парсера:+[[wiki:plugin:parserarray|Плагин Parserarray]] — это экспортный рендерер, который показывает инструкции для текущей страницы. Он может помочь вам понять формат данных. Ниже показан пример сырого текста вики и соответствующий вывод парсера;
  
 Исходный текст (содержит таблицу): Исходный текст (содержит таблицу):
Строка 498: Строка 529:
  
 <code> <code>
-Array +Array( 
-+    [0] => Array(
-    [0] => Array +
-        (+
             [0] => document_start             [0] => document_start
-            [1] => Array +            [1] => Array()
-                ( +
-                ) +
             [2] => 0             [2] => 0
         )         )
- +    [1] => Array(
-    [1] => Array +
-        (+
             [0] => p_open             [0] => p_open
-            [1] => Array +            [1] => Array()
-                ( +
-                ) +
             [2] => 0             [2] => 0
         )         )
- +    [2] => Array(
-    [2] => Array +
-        (+
             [0] => cdata             [0] => cdata
-            [1] => Array +            [1] => Array(
-                (+
                     [0] =>                      [0] => 
  
 abc abc
                 )                 )
- 
             [2] => 0             [2] => 0
         )         )
- +    [3] => Array(
-    [3] => Array +
-        (+
             [0] => p_close             [0] => p_close
-            [1] => Array +            [1] => Array()
-                ( +
-                ) +
             [2] => 5             [2] => 5
         )         )
- +    [4] => Array(
-    [4] => Array +
-        (+
             [0] => table_open             [0] => table_open
-            [1] => Array +            [1] => Array(
-                (+
                     [0] => 3                     [0] => 3
                     [1] => 2                     [1] => 2
                 )                 )
- 
             [2] => 5             [2] => 5
         )         )
- +    [5] => Array(
-    [5] => Array +
-        (+
             [0] => tablerow_open             [0] => tablerow_open
-            [1] => Array +            [1] => Array()
-                ( +
-                ) +
             [2] => 5             [2] => 5
         )         )
- +    [6] => Array(
-    [6] => Array +
-        (+
             [0] => tablecell_open             [0] => tablecell_open
-            [1] => Array +            [1] => Array(
-                (+
                     [0] => 1                     [0] => 1
                     [1] => left                     [1] => left
                 )                 )
- 
             [2] => 5             [2] => 5
         )         )
- +    [7] => Array(
-    [7] => Array +
-        (+
             [0] => cdata             [0] => cdata
-            [1] => Array +            [1] => Array(
-                (+
                     [0] =>  Row 0 Col 1                     [0] =>  Row 0 Col 1
                 )                 )
- 
             [2] => 7             [2] => 7
         )         )
- +    [8] => Array(
-    [8] => Array +
-        (+
             [0] => cdata             [0] => cdata
-            [1] => Array +            [1] => Array(
-                (+
                     [0] =>                          [0] =>     
                 )                 )
- 
             [2] => 19             [2] => 19
         )         )
- +    [9] => Array(
-    [9] => Array +
-        (+
             [0] => tablecell_close             [0] => tablecell_close
-            [1] => Array +            [1] => Array()
-                ( +
-                ) +
             [2] => 23             [2] => 23
         )         )
- +    [10] => Array(
-    [10] => Array +
-        (+
             [0] => tablecell_open             [0] => tablecell_open
-            [1] => Array +            [1] => Array(
-                (+
                     [0] => 1                     [0] => 1
                     [1] => left                     [1] => left
                 )                 )
- 
             [2] => 23             [2] => 23
         )         )
- +    [11] => Array(
-    [11] => Array +
-        (+
             [0] => cdata             [0] => cdata
-            [1] => Array +            [1] => Array(
-                (+
                     [0] =>  Row 0 Col 2                     [0] =>  Row 0 Col 2
                 )                 )
- 
             [2] => 24             [2] => 24
         )         )
- +    [12] => Array(
-    [12] => Array +
-        (+
             [0] => cdata             [0] => cdata
-            [1] => Array +            [1] => Array(
-                (+
                     [0] =>                           [0] =>      
                 )                 )
- 
             [2] => 36             [2] => 36
         )         )
- +    [13] => Array(
-    [13] => Array +
-        (+
             [0] => tablecell_close             [0] => tablecell_close
-            [1] => Array +            [1] => Array()
-                ( +
-                ) +
             [2] => 41             [2] => 41
         )         )
- +    [14] => Array(
-    [14] => Array +
-        (+
             [0] => tablecell_open             [0] => tablecell_open
-            [1] => Array +            [1] => Array(
-                (+
                     [0] => 1                     [0] => 1
                     [1] => left                     [1] => left
                 )                 )
- 
             [2] => 41             [2] => 41
         )         )
- +    [15] => Array(
-    [15] => Array +
-        (+
             [0] => cdata             [0] => cdata
-            [1] => Array +            [1] => Array(
-                (+
                     [0] =>  Row 0 Col 3                     [0] =>  Row 0 Col 3
                 )                 )
- 
             [2] => 42             [2] => 42
         )         )
- +    [16] => Array(
-    [16] => Array +
-        (+
             [0] => cdata             [0] => cdata
-            [1] => Array +            [1] => Array(
-                (+
                     [0] =>                              [0] =>         
                 )                 )
- 
             [2] => 54             [2] => 54
         )         )
- +    [17] => Array(
-    [17] => Array +
-        (+
             [0] => tablecell_close             [0] => tablecell_close
-            [1] => Array +            [1] => Array()
-                ( +
-                ) +
             [2] => 62             [2] => 62
         )         )
- +    [18] => Array(
-    [18] => Array +
-        (+
             [0] => tablerow_close             [0] => tablerow_close
-            [1] => Array +            [1] => Array()
-                ( +
-                ) +
             [2] => 63             [2] => 63
         )         )
- +    [19] => Array(
-    [19] => Array +
-        (+
             [0] => tablerow_open             [0] => tablerow_open
-            [1] => Array +            [1] => Array()
-                ( +
-                ) +
             [2] => 63             [2] => 63
         )         )
- +    [20] => Array(
-    [20] => Array +
-        (+
             [0] => tablecell_open             [0] => tablecell_open
-            [1] => Array +            [1] => Array(
-                (+
                     [0] => 1                     [0] => 1
                     [1] => left                     [1] => left
                 )                 )
- 
             [2] => 63             [2] => 63
         )         )
- +    [21] => Array(
-    [21] => Array +
-        (+
             [0] => cdata             [0] => cdata
-            [1] => Array +            [1] => Array(
-                (+
                     [0] =>  Row 1 Col 1                     [0] =>  Row 1 Col 1
                 )                 )
- 
             [2] => 65             [2] => 65
         )         )
- +    [22] => Array(
-    [22] => Array +
-        (+
             [0] => cdata             [0] => cdata
-            [1] => Array +            [1] => Array(
-                (+
                     [0] =>                          [0] =>     
                 )                 )
- 
             [2] => 77             [2] => 77
         )         )
- +    [23] => Array(
-    [23] => Array +
-        (+
             [0] => tablecell_close             [0] => tablecell_close
-            [1] => Array +            [1] => Array()
-                ( +
-                ) +
             [2] => 81             [2] => 81
         )         )
- +    [24] => Array(
-    [24] => Array +
-        (+
             [0] => tablecell_open             [0] => tablecell_open
-            [1] => Array +            [1] => Array(
-                (+
                     [0] => 1                     [0] => 1
                     [1] => left                     [1] => left
                 )                 )
- 
             [2] => 81             [2] => 81
         )         )
- +    [25] => Array(
-    [25] => Array +
-        (+
             [0] => cdata             [0] => cdata
-            [1] => Array +            [1] => Array(
-                (+
                     [0] =>  Row 1 Col 2                     [0] =>  Row 1 Col 2
                 )                 )
- 
             [2] => 82             [2] => 82
         )         )
- +    [26] => Array(
-    [26] => Array +
-        (+
             [0] => cdata             [0] => cdata
-            [1] => Array +            [1] => Array(
-                (+
                     [0] =>                           [0] =>      
                 )                 )
- 
             [2] => 94             [2] => 94
         )         )
- +    [27] => Array(
-    [27] => Array +
-        (+
             [0] => tablecell_close             [0] => tablecell_close
-            [1] => Array +            [1] => Array()
-                ( +
-                ) +
             [2] => 99             [2] => 99
         )         )
- +    [28] => Array(
-    [28] => Array +
-        (+
             [0] => tablecell_open             [0] => tablecell_open
-            [1] => Array +            [1] => Array(
-                (+
                     [0] => 1                     [0] => 1
                     [1] => left                     [1] => left
                 )                 )
- 
             [2] => 99             [2] => 99
         )         )
- +    [29] => Array(
-    [29] => Array +
-        (+
             [0] => cdata             [0] => cdata
-            [1] => Array +            [1] => Array(
-                (+
                     [0] =>  Row 1 Col 3                     [0] =>  Row 1 Col 3
                 )                 )
- 
             [2] => 100             [2] => 100
         )         )
- +    [30] => Array(
-    [30] => Array +
-        (+
             [0] => cdata             [0] => cdata
-            [1] => Array +            [1] => Array(
-                (+
                     [0] =>                              [0] =>         
                 )                 )
- 
             [2] => 112             [2] => 112
         )         )
- +    [31] => Array(
-    [31] => Array +
-        (+
             [0] => tablecell_close             [0] => tablecell_close
-            [1] => Array +            [1] => Array()
-                ( +
-                ) +
             [2] => 120             [2] => 120
         )         )
- +    [32] => Array(
-    [32] => Array +
-        (+
             [0] => tablerow_close             [0] => tablerow_close
-            [1] => Array +            [1] => Array()
-                ( +
-                ) +
             [2] => 121             [2] => 121
         )         )
- +    [33] => Array(
-    [33] => Array +
-        (+
             [0] => table_close             [0] => table_close
-            [1] => Array +            [1] => Array()
-                ( +
-                ) +
             [2] => 121             [2] => 121
         )         )
- +    [34] => Array(
-    [34] => Array +
-        (+
             [0] => p_open             [0] => p_open
-            [1] => Array +            [1] => Array()
-                ( +
-                ) +
             [2] => 121             [2] => 121
         )         )
- +    [35] => Array(
-    [35] => Array +
-        (+
             [0] => cdata             [0] => cdata
-            [1] => Array +            [1] => Array(
-                (+
                     [0] => def                     [0] => def
  
                 )                 )
- 
             [2] => 122             [2] => 122
         )         )
- +    [36] => Array(
-    [36] => Array +
-        (+
             [0] => p_close             [0] => p_close
-            [1] => Array +            [1] => Array()
-                ( +
-                ) +
             [2] => 122             [2] => 122
         )         )
- +    [37] => Array(
-    [37] => Array +
-        (+
             [0] => document_end             [0] => document_end
-            [1] => Array +            [1] => Array()
-                ( +
-                ) +
             [2] => 122             [2] => 122
         )         )
- 
 ) )
 </code> </code>
  
-Верхний уровень массива --- это просто список. Каждый из его дочерних элементов описывает возвратную функцию, которая будет запущена под преобразователем (см. описание [[#преобразователь|преобразователя]] ниже), также как и индекс байта исходного текста, где был найден особенный «элемент» синтаксиса вики.+Верхний уровень массива --- это просто список. Каждый из его дочерних элементов описывает возвратную функцию, которая будет запущена под преобразователем (см. описание [[#Renderer (преобразователь)|Renderer]] ниже), также как и индекс байта исходного текста, где был найден особенный «элемент» синтаксиса вики.
  
 === Единственная инструкция === === Единственная инструкция ===
Строка 929: Строка 790:
  
                 )                 )
- 
             [2] => 122             [2] => 122
         )         )
 </code> </code>
  
-Первый элемент (индекс 0 ) --- это наименование метода или функции, исполняемой преобразователем.+Первый элемент (индекс 0) — это имя метода или функции в Rendererкоторую необходимо выполнить.
  
-Второй элемент (индекс 1) --- сам является массивом, каждый из элементов //которого// будет аргументом вызываемого метода преобразователя.+Второй элемент (индекс 1) сам по себе является массивом, каждый из элементов которого является аргументом для метода Renderer, который будет вызван.
  
-В этом случае это будет единственный аргумент со значением ''%%"def\n"%%'', так что вызов метода будет:+В этом случае имеется один аргумент со значением ''%%"def\n"%%'', поэтому вызов метода будет выглядеть так:
  
 <code php> <code php>
Строка 944: Строка 804:
 </code> </code>
  
-Третий элемент (индекс 2) --- является индексом байта первого символа, на котором «сработает» эта инструкция в исходном тексте. Он должен быть точно таким же, как и значение, возвращённое PHP-функцией «[[phpfn>strpos]]». Это может использоваться для обнаружения секции исходного текста викиоснованной на позиции сгенерированной инструкции (позже будет пример).+Третий элемент (индекс 2) — это индекс байта первого символа, который «запустил» эту инструкцию в необработанном текстовом документе. Он должен быть таким же, как значение, возвращаемое функцией PHP [[phpfn>strpos]]. Это можно использовать для извлечения разделов необработанного текста вики на основе позиций сгенерированных из него инструкций (пример ниже).
  
-**Замечание:** метод ''parse'' парсера разбивает исходный вики текст на предыдущий и последующий символы, чтобы гарантировать корректный выход анализатора из состояний, так что вам требуется вычесть единицу из индекса байта, чтобы получить корректную позицию оригинального исходного вики-текстаТакже парсер нормализует строки под стиль Unix’а (т. е. все''%%\r\n%%'' становятся ''%%\n%%''), так что документ, который видит анализатор, может быть меньше, чем тот, который вы в действительности загрузили.+**Примечание**: Метод парсера ''parse'' дополняет необработанный текст вики предшествующим и последующим символом перевода строки, чтобы гарантировать корректный выход определенных состояний лексерапоэтому вам может потребоваться вычесть из индекса байта, чтобы получить правильное местоположение в исходном необработанном тексте викиПарсер также нормализует переводы строк в соответствии со стилем Unix (т. е. все ''%%\r\n%%'' становятся ''%%\n%%''), поэтому документ, который видит лексер, может быть меньше того, который вы ему фактически дали.
  
-Пример массив инструкций страницы с описанием [[wiki:syntax|синтаксиса]] --- [[devel:parser:sample_instructions]].+Пример массив инструкций страницы с описанием [[wiki:syntax|синтаксиса]] можно найти [[wiki:devel:parser:sample_instructions|здесь]].
  
-==== Преобразователь ====+==== Renderer (преобразователь====
  
-Преобразователь --- это класс (или коллекция функций), определяемый вами. Его интерфейс описан в файле ''inc/parser/renderer.php'' и выглядит так:+Renderer (преобразователь--- это класс (или коллекция функций), определяемый вами. Его интерфейс описан в файле ''inc/parser/renderer.php'' и выглядит так:
  
 <code php> <code php>
Строка 958: Строка 818:
 class Doku_Renderer { class Doku_Renderer {
  
-    // snip+    // вырезка
          
-    function header($text, $level) {}+    public function header($text, $level) {}
          
-    function section_open($level) {}+    public function section_open($level) {}
          
-    function section_close() {}+    public function section_close() {}
          
-    function cdata($text) {}+    public function cdata($text) {}
          
-    function p_open() {}+    public function p_open() {}
          
-    function p_close() {}+    public function p_close() {}
          
-    function linebreak() {}+    public function linebreak() {}
          
-    function hr() {}+    public function hr() {}
          
-    // snip+    // вырезка
 } }
 </code> </code>
  
-Он используется для документирования преобразователя, хотя также может быть расширен, если вы захотите написать преобразователь, который лишь перехватывает определённые вызовы.+Он используется для документирования Renderer, хотя его также можно расширить, если вы хотите написать Renderer, который захватывает только определенные вызовы.
  
-Основной принцип того, как инструкции, возвращаемые парсером, используются преобразователем, близок по смыслу к [[wp>ru:SAX|SAX XML API]] --- инструкции являются перечнем имён функций / методов и их аргуменов. Каждая инструкция может быть вызвана через преобразователь (т. е. реализуемые им методы являются [[wp>ru:Callback_(программирование)|обратными]]). В отличие от «SAX API», где доступно совсем немного, достаточно общих, обратно вызываемых методов (например, tag_start, tag_end, cdata и т. д.), преобразователь определяет более точную API, где методы обычно соответствуют один-к-одному действию по генерации выходных данных.+Основной принцип того, как инструкции, возвращаемые парсером, используются против Renderer, аналогичен понятию [[wp>Simple_API_for_XML|SAX XML API]] - инструкции представляют собой список имен функций/методов и их аргументов. Проходя по списку инструкций, каждая инструкция может быть вызвана против Renderer (т. е. методы, предоставляемые Renderer, являются [[wp>Callback_(computer_science)|callbacks]]). Unlike the SAX API, where only a few, fairly general, callbacks are available (e.g. tag_start, tag_end, cdata etc.). В отличие от SAX API , где доступно только несколько, довольно общих, обратных вызовов (например, tag_start, tag_end, cdata и т. д.), Renderer определяет более явный API , где методы обычно соответствуют один к одному акту генерации вывода. В разделе Renderer, показанном выше, методы ''p_open'' и ''p_close'' будут использоваться для вывода тегов ''%%<p>%%'' и ''%%</p>%%'' в XHTML, соответственно, в то время как ''header'' функция принимает два аргумента — некоторый текст для отображения и «уровень» заголовка, поэтому вызов типа ''%%header('Some Title', 1)%%'' будет выведен в XHTML типа ''%%<h1>Some Title</h1>%%''.
  
-Во фрагменте преобразователя, показанном выше методы ''p_open'' и ''p_close'' будут использованы для вывода тэгов ''%%<p>%%'' и ''%%</p>%%'' в XHTML, соответственно, в то время, как функция ''header'' принимает два аргумента --- некоторый текст для отображения и «уровень» заголовка, так что вызов типа ''%%header('Some Title',1)%%'' выведет в XHTML ''%%<h1>Some Title</h1>%%''.+=== Вызов рендерера с инструкциями ===
  
-=== Вызов преобразователя через инструкции === +Клиентскому кодуиспользующему Parser, остается выполнить список инструкций для Renderer. Обычно это делается с помощью функции PHP [[phpfn>call_user_func_array()]] function. Например;
- +
-К **клиентскому коду** относится использование парсера для выполнения перечня инструкций через преобразователь. Обычно это делается использованием php-функции «[[phpfn>call_user_func_array]]». Например:+
  
 <code php> <code php>
-// Получить перечень инструкций из парсера +// Получить список инструкций от парсера  
-$instructions = $Parser->parse($rawDoc);+$instructions = $parser->parse($rawDoc);
  
-// Создать преобразователь +// Создаем рендерер  
-$Renderer new Doku_Renderer_XHTML();+$renderer = new Doku_Renderer_xhtml();
  
-// Пройтись по всем инструкциям +// Проходим по инструкциям  
-foreach ( $instructions as $instruction ) { +foreach ($instructions as $instruction) { 
-     +    // Выполняем обратный вызов для Renderer  
-    // Выполнить инструкции через преобразователь +    call_user_func_array([$renderer, $instruction[0]], $instruction[1]);
-    call_user_func_array(array(&$Renderer, $instruction[0]),$instruction[1]);+
 } }
 </code> </code>
  
-=== Методы преобразователя для ссылок ===+=== Методы связи с рендерером ===
  
-Ключевыми методами преобразователя для обработки различного рода ссылок являются:+Ключевые методы Renderer для обработки различных типов ссылок:
  
-  * ''%%function camelcaselink($link) {} // $link вида «SomePage"%%'' +  * ''function [[xref>camelcaselink($link)]] %%{} // $link like "SomePage"%%'' 
-    * Возможно, это будет проигнорировано проверкой на спам-адрес --- маловероятно, что кто-нибудь подобным образом поставить ссылку вне сайта. +    *Вероятно, это можно проигнорировать для проверки на спам — никто не должен иметь возможности ссылаться на сторонние сайты с таким синтаксисом
-  * ''%%function internallink($link, $title = NULL) {} // $link вида «[[syntax]]"%%'' +  * ''function [[xref>internallink($link, $title = null)]]%% {} // $link like "[[syntax]]"%%'' 
-    * Хотя ''$link'' сама по себе является внутренней, ''$title'' может быть недоступным изображением, так что требуется проверка. +    *Хотя ''$link'' сам по себе является внутренним, ''$title'' может быть изображением, которое находится вне сайта, поэтому необходимо проверить 
-  * ''%%function externallink($link, $title = NULL) {}%%'' +  * ''function [[xref>externallink($link, $title = null)]] {}'' 
-    * И ''$link''и ''$title'' (изображениетребуют проверки. +    *Оба изображения ''$link'' и ''$title'' (изображениянуждаются в проверке 
-  * ''%%function interwikilink($link, $title = NULL, $wikiName, $wikiUri) {}%%'' +  * ''function [[xref>interwikilink($link, $title = null, $wikiName, $wikiUri)]] {}'' 
-    * ''$title'' требует проверки для изображений. +    *Необходимость ''$title'' проверки изображений 
-  * ''%%function filelink($link, $title = NULL) {}%%'' +  * ''function [[xref>filelink($link, $title = null)]] {}'' 
-    * Техническитолько годные ''%%file://%%'' URL будут совпадать, но всё равно лучше проверить плюс проверка ''$title'', которое может быть недоступным изображением. +    *Технически должны совпадать только действительные ''%%file://%%'' URLдреса, новероятнолучше все равно проверитьплюс ''$title'' может быть стороннее изображение 
-  * ''%%function windowssharelink($link, $title = NULL) {}%%'' +  * ''function [[xref>windowssharelink($link, $title = null)]] {}'' 
-    * Требуется проверить только годные адреса доступа к общим ресурсам Windows, но всё равно лучше проверить плюс проверка ''$title'', которое может быть недоступным изображением. +    *Должен соответствовать только допустимым URL-адресам общих ресурсов Windows, но в любом случае проверять наличие ''$title'' изображений 
-  * ''%%function email($address, $title = NULL) {}%%'' +  * ''function [[xref>emaillink($address, $title = null)]] {}'' 
-    * ''$title'' может быть изображением. Проверять ли адрес электропочты+    *''$title'' может быть изображение. Проверить почту тоже?$titleможет быть изображение. Проверить почту тоже
-  * ''%%function internalmedialink ($src,$title=NULL,$align=NULL,$width=NULL,$height=NULL,$cache=NULL) {}%%'' +  * ''function [[xref>internalmedialink($src, $title = null, $align = null $width = null, $height = null, $cache = null)]] {}'' 
-    * Здесь проверка не требуется --- следует только поставить ссылки на локальные изображения. ''$title'' сам по себе не может быть изображением. +    *Это не требует проверки — должно ссылаться только на локальные изображения. ''$title'' само по себе не может быть изображением 
-  * ''%%function externalmedialink($src,$title=NULL,$align=NULL,$width=NULL,$height=NULL,$cache=NULL) {}%%'' +  * ''function [[xref>externalmedialink($src, $title = null, $align = null, $width = null, $height = null, $cache = null)]] {}'' 
-    * ''$src'' требует проверки.+    *''$src'' нуждается в проверке
  
-Особое внимание следует уделит методам, принимающим в качестве параметра ''%%$title%%'', который представляет видимый текст ссылки, например:+Особого внимания требуют методыкоторые принимают''%%$title%%'' аргумент, представляющий видимый текст ссылки, например;
  
 <code html> <code html>
-<a href="http://www.example.com/">This is the title</a>+<a href="https://www.example.com">This is the title</a>
 </code> </code>
  
-Аргумент ''%%$title%%'' может принимать три возможных типа значений:+Аргумент ''%%$title%%'' может иметь три возможных типа значений;
  
-  - ''NULL'': у документа вики нет заголовка; +  - ''null'': в вики-документе заголовок не указан. 
-  - строка: в качестве заголовка использована простая тестовая строка; +  - string: в качестве заголовка использовалась простая текстовая строка 
-  - массив (хэш): в качестве заголовка использовано изображение.+  - array (hash): в качестве заголовка использовано изображение.
  
-Если ''%%$title%%'' является массивом, он будет содержать ассоциированные значения, описывающие изображение:+Если это ''%%$title%%'' массив, он будет содержать ассоциативные значения, описывающие изображение;
  
 <code php> <code php>
-$title = array( +$title = [ 
-    // Может быть 'internalmedia' (локальное изображение) или 'externalmedia' (внешнее изображение) +    // Может быть 'internalmedia' (локальное изображение) или 'externalmedia' (внешнее изображение)  
-    'type'=>'internalmedia',+    'type' => 'internalmedia',
          
-    // URL изображения (может быть вики-URL или http://static.example.com/img.png) +    // URL-адрес изображения (может быть URL-адресом wiki или https://static.example.com/img.png)  
-    'src'=>'wiki:php-powered.png',+    'src' => 'wiki:php-powered.png',
          
-    // Для альтернативного атрибута - a string or NULL +    // Для атрибута alt строка или null  
-    'title'=>'Powered by PHP',+    'title' => 'Powered by PHP',
          
-    // 'left', 'right', 'center' или NULL +    // 'left', 'right', 'center' или null 
-    'align'=>'right',+    'align' => 'right',
          
-    // Ширина в пикселях или NULL +    // Ширина в пикселях или null  
-    'width'=> 50,+    'width' => 50,
          
-    // Высота в пикселях или NULL +    // Высота в пикселях или null  
-    'height'=>75,+    'height' => 75,
          
-    // Следует ли кэшировать изображение (для внешних изображений)? +    // Кэшировать ли изображение (для внешних изображений) 
-    'cache'=>FALSE+    'cache' => false
-);+];
 </code> </code>
  
wiki/devel/parser.1737049981.txt.gz · Последнее изменение: vladpolskiy