DokuWiki 重新解析和嵌入语法

核心概念

在 DokuWiki 的解析系统中,重新解析是指当插件或特殊语法捕获了一段文本后,需要手动创建新的解析器实例来重新处理这段文本中的 wiki 语法。

为什么需要重新解析

解析器的单次遍历设计

DokuWiki 的词法分析器采用单次遍历设计。在主解析循环中: Lexer.php:142-154

一旦文本被某个模式匹配和消费,就不会再回到解析队列中重新处理。

DOKU_LEXER_UNMATCHED 状态的处理

当文本在当前解析上下文中没有被任何模式匹配时,会被标记为 DOKU_LEXER_UNMATCHED 状态,这些文本会直接转换为 cdata 指令: handler.php:314-316

在 XHTML 渲染器中,cdata() 方法只是简单地转义 HTML 实体,不进行任何语法解析:

重新解析的实现方法

核心函数组合

重新解析主要通过 p_render() + p_get_instructions() 组合实现:

这个函数创建全新的解析器和处理器实例,重新应用所有解析模式来处理文本。

插件中的使用

DokuWiki 提供了 render_text() 方法供插件使用:

使用场景

1. 语法插件中的嵌套渲染

当插件捕获包含 wiki 语法的文本块时,需要重新解析以支持嵌套语法。

2. 命令行工具

在命令行渲染工具中处理任意文本:

3. 页面预览功能

处理用户输入的文本片段:

容器类插件的特殊情况

即使是容器类插件也需要手动解析。容器类插件在解析器模式分类中属于特殊类型:

但它们在处理 DOKU_LEXER_UNMATCHED 文本时,仍然遵循相同的机制。

getAllowedTypes() 的作用

getAllowedTypes() 方法定义插件可以接受的嵌套模式类型: SyntaxPlugin.php:40-43

这个方法在 accepts() 中被使用来构建允许的模式列表: SyntaxPlugin.php:111-130

但这只是声明性配置,告诉解析器插件的能力,实际的内容处理仍需手动实现。

格式化语法的处理

对于嵌套格式化标签(如粗体、斜体等),DokuWiki 使用 nestingTag() 方法统一处理: handler.php:251-264

这些格式化语法都通过相同的模式处理: handler.php:411-415

设计理念

这种设计让插件开发者可以灵活控制内容处理:

  • 代码块插件需要保持原始文本,不解析任何语法
  • 容器类插件可能需要支持完整的 wiki 语法解析

DokuWiki 让插件自己决定是否需要重新解析内容,确保了解析的可控性和性能优化。

Notes

重新解析机制是 DokuWiki 支持复杂嵌套语法的关键,但会带来性能开销。这就是为什么 DokuWiki 在正常页面渲染中使用缓存机制,并让插件开发者明确选择是否需要重新解析的原因。

1. 容器类插件示例

容器类插件需要在容器内支持标准的 wiki 语法。从代码中可以看到,插件可以使用 PluginTrait 提供的 render_text() 方法: PluginTrait.php:274-277

一个典型的容器类插件实现示例:

public function render($format, Doku_Renderer $renderer, $data) {  
    if ($format == 'xhtml') {  
        $renderer->doc .= '<div class="wrap-container">';  
        // 重新解析容器内的 wiki 语法  
        $html = $this->render_text($data['content'], 'xhtml');  
        $renderer->doc .= $html;  
        $renderer->doc .= '</div>';  
        return true;  
    }  
    return false;  
}

2. 包含类插件示例

包含类插件需要渲染包含的页面内容。DokuWiki 核心已经提供了这种功能的实现,可以在模板函数中看到:

包含类插件的实现示例:

public function render($format, Doku_Renderer $renderer, $data) {  
    if ($format == 'xhtml') {  
        // 使用 p_wiki_xhtml 渲染包含的页面  
        $html = p_wiki_xhtml($data['pageid'], '', false);  
        $renderer->doc .= $html;  
        return true;  
    }  
    return false;  
}

3. 模板类插件示例

模板类插件需要处理模板内容中的 wiki 语法。在页面预览功能中可以看到类似的实现: PageView.php:56

模板类插件的实现示例:

public function render($format, Doku_Renderer $renderer, $data) {  
    if ($format == 'xhtml') {  
        // 处理模板变量替换  
        $template_content = str_replace('{{title}}', $data['title'], $data['template']);  
        $template_content = str_replace('{{content}}', $data['content'], $template_content);  

        // 重新解析模板中的 wiki 语法  
        $instructions = p_get_instructions($template_content);  
        $html = p_render('xhtml', $instructions, $info);  
        $renderer->doc .= $html;  
        return true;  
    }  
    return false;  
}

核心解析函数

所有这些插件都依赖于 DokuWiki 的核心解析函数: parserutils.php:219-234

这个函数创建新的解析器实例,重新应用所有解析模式来处理文本。

Notes

这些示例展示了不同类型插件如何使用重新解析机制。容器类插件使用 render_text() 方法,包含类插件使用 p_wiki_xhtml() 函数,而模板类插件直接使用 p_render() + p_get_instructions() 组合。所有这些方法的核心都是重新创建解析器来处理嵌套的 wiki 语法。

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇