Skip to main content

QParse

将结构化 Markdown 教案渲染为 Word(DOCX),并支持 .qmd 单文件打包分发。

典型场景:数学备课 / 习题讲义。支持:

  • @import 分题导入
  • $...$ LaTeX 公式
  • 填空 / 选择 / 多选 / 简答
  • 自动生成参考答案
  • Markdown 表格与 HTML 表格
  • 图片、分页、主题模板
  • .qmd 打包 / 解包(资源按 SHA-256 去重)

目录结构

QParse/
├── qparse/                     # 核心库
│   ├── markdwon_loader.py      # Markdown 加载、@import、题号装饰
│   ├── markdwon_render.py      # render.md 解析与整篇渲染
│   ├── markdwon_document/      # 文档节点树(题干/答案/表格/图片)
│   ├── docx_render/            # Pandoc + python-docx 输出 DOCX
│   ├── render_option/          # 默认主题、模板、referance.docx
│   ├── qmd_packer.py           # .qmd 打包
│   ├── qmd_unpacker.py         # .qmd 解包
│   └── utils/                  # 空格/换行保护等工具
├── qmd_cli.py                  # Typer 命令行入口
├── dev.py                      # 开发调试脚本
├── render.md                   # 渲染入口配置示例
├── QParse.code-workspace       # 工作区(代码 + 备课目录)
├── qmd-package-design.md       # .qmd 设计说明
└── README.md

环境依赖

建议使用项目内虚拟环境:

cd d:\dev\QParse
.\venv\Scripts\activate

主要依赖:

包 用途
beautifulsoup4 HTML/Markdown 中间结构解析
pypandoc + Pandoc Markdown/HTML → DOCX
python-docx DOCX 后处理(表格、边框、图片)
docxcompose 多段 DOCX 合并
jinja2 题干/答案模板渲染
typer 命令行工具

系统需已安装 Pandoc。


快速开始

1. 为 main.md 生成 render.md

python qmd_cli.py init "d:\workspace\lesson_plan\...\main.md" -o ".\render.md" -f

生成示例:

<render src="D:\workspace\...\main.md">
    <file type="docx" dist="习题版.docx">
        <doc theme="Worksheet">
            <after>
<pagebreak></pagebreak>
# 参考答案

<reference-answer></reference-answer>

            </after>
        </doc>
    </file>
</render>

2. 直接渲染 DOCX

python qmd_cli.py render .\render.md

3. 打包为 .qmd 再解包渲染

# 打包
python qmd_cli.py pack .\render.md -o .\lesson.qmd

# 解包(目录保留)
python qmd_cli.py unpack .\lesson.qmd -t .\lesson_unpacked

# 渲染解包后的入口
python qmd_cli.py render .\lesson_unpacked\render.md

# 或一键:打包 → 解包 → 渲染
python qmd_cli.py build .\render.md -o .\lesson.qmd -u .\lesson_unpacked

命令行工具

入口文件:qmd_cli.py

python qmd_cli.py --help
命令 说明
init 输入 main.md,生成默认 render.md
pack 将 render.md 及依赖打包为 .qmd
unpack 解包 .qmd 到工作目录
render 根据 render.md 渲染 DOCX
build 打包 + 解包 + 渲染一键完成

init

python qmd_cli.py init <main.md> [-o render.md] [-d 习题版.docx] [--theme Worksheet] [-f]
  • 默认输出到 main.md 同级的 render.md
  • -o 可指定输出路径(例如项目根目录)
  • -f 覆盖已存在文件

pack

python qmd_cli.py pack <render.md> [-o lesson.qmd] [-w QParse.code-workspace]

unpack

python qmd_cli.py unpack <lesson.qmd> [-t lesson_unpacked]

render

python qmd_cli.py render <render.md>

build

python qmd_cli.py build <render.md> [-o lesson.qmd] [-u lesson_unpacked]

Python API

from qparse import (
    MarkdownLoader,
    MarkdwonRender,
    QmdPacker,
    QmdUnpacker,
)

# 加载 Markdown(展开 @import,装饰题号)
loader = MarkdownLoader(r"d:\path\to\main.md")
soup = loader.get_soup()
answers = loader.get_reference_answer_markdwon()

# 按 render.md 渲染
render = MarkdwonRender(src=r"d:\dev\QParse\render.md")
outputs = render.render()  # List[Path]

# 打包 / 解包
packer = QmdPacker()
qmd_path = packer.pack(entry=r"d:\dev\QParse\render.md", output=r"d:\dev\QParse\lesson.qmd")

unpacker = QmdUnpacker(str(qmd_path))
work_dir = unpacker.unpack(target=r"d:\dev\QParse\lesson_unpacked")
entry = unpacker.entry_path

开发调试可参考 dev.py:

python dev.py

Markdown 约定

分文件导入

@import "./01/main.md"
@import "./02/main.md"

题目结构(示意)

<question>
  <stem>
    在 $\triangle ABC$ 中,……(  )。
  </stem>
  <span class="chiose">C</span>
</question>

题型 class:

class 含义
blank 填空
chiose / choice 单选
multiple-choice / multiple-chiose 多选
answer 简答

Loader 会自动:

  1. 为每个 <question> 写入连续 question_id
  2. 标记 span[type=answer]
  3. 写入 answer_types

参考答案

在 render.md 的 before / after 中使用:

<reference-answer></reference-answer>

生成规则:

  • 填空 / 选择 / 多选:连续客观题合并为 Markdown 表格
  • 简答:题号、答案(使用顿号,避免 Pandoc 识别为有序列表)
  • 答案只取文本,不保留原始 <span>

示例:

| 1 | 2 |
| --- | --- |
| $\sqrt{3}-1$ | C |

3、(Ⅰ)$\frac{8\sqrt{10}}{9}$;(Ⅱ)$\frac{\sqrt{6}}{2}$

公式与换行

  • 行内公式:$...$
  • 源文件中的 \n 在加载阶段转为 <br/>,DOCX 使用 Pandoc hard_line_breaks
  • 普通空格与 Tab 经 HtmlFullProtector 保护,避免 BeautifulSoup 丢失

图片

![说明](./assets/img/demo.png)

打包时图片进入 resources/<sha256>.ext,解包后复制到文档同级 assets/。


render.md 说明

render.md 是渲染编排入口,不是正文本身。

<render src="绝对或相对路径/main.md" theme="可选主题json">
    <file type="docx" dist="习题版.docx">
        <doc theme="Worksheet">
            <before>…</before>
            <after>
                <pagebreak></pagebreak>
                # 参考答案
                <reference-answer></reference-answer>
            </after>
        </doc>
    </file>
</render>

要点:

  • src:正文 main.md(相对路径相对 render.md 所在目录解析)
  • file@dist:输出 DOCX 文件名/路径
  • doc@theme:主题名(来自默认 theme 或外部 json)
  • before / after:插入正文前后的内容
  • <reference-answer>:自动替换为参考答案 Markdown

DOCX 渲染流程

render.md
  → MarkdownLoader 加载入口与正文
  → 展开 @import / 图片 / 题号
  → before/after 插入(含参考答案)
  → MarkdwonDocument 生成中间 Markdown/HTML buffer
  → Pandoc 转 DOCX(tex_math_dollars + hard_line_breaks + reference-doc)
  → python-docx 后处理表格样式、图片、合并
  → 复制到 dist
  → 清理本次 .qmd_runtime/<uuid>

表格相关默认配置(可在 render_option 中调整):

  • 宽度 100%
  • 表头加粗
  • 表头底色
  • 边框颜色
  • 单元格居中

并发渲染时,每个 DocxRender 使用独立临时子目录,避免互相删除文件。


.qmd 打包设计(摘要)

详细设计见 qmd-package-design.md。

包内结构:

lesson.qmd
├── manifest.json
├── render.md
├── documents/          # 保持目录关系的 Markdown
├── resources/          # 二进制资源,按 SHA-256 去重
├── themes/
└── templates/

规则:

  1. 绝对路径资源复制后转为包内相对路径
  2. 相同内容只存一份(哈希去重)
  3. 解包时按需把资源放到各 Markdown 同级 assets/
  4. 编辑器可直接预览 ./assets/...
  5. 重新打包时重新计算哈希并清理未引用资源

工作区

QParse.code-workspace 通常包含:

  1. 代码目录:d:\dev\QParse
  2. 备课目录:如 02-必修2备课

打包器会读取 workspace folders,将文档放入:

documents/<index>-<folder-name>/...

避免多个工作区目录同名冲突。


常见问题

1. 简答题被识别成 Word 有序列表

参考答案使用 3、 而不是 3.。

2. 解包后找不到 main.md

MarkdwonRender 会把 render.md 中的相对 src 解析为相对 render.md 所在目录。请用解包后的 render.md 作为渲染入口。

3. 两个进程同时渲染报临时文件不存在

临时目录已改为 .qmd_runtime/<uuid>/,每个渲染实例独立。

4. 表格公式丢失

Markdown 分支使用:

markdown+tex_math_dollars+hard_line_breaks

HTML 表格分支使用:

html+tex_math_dollars

5. 图片在打包后预览失败

确认解包步骤已执行;图片应出现在对应 Markdown 同级 assets/ 下。


开发提示

  • 项目内历史拼写 markdwon 为既有命名,调用时请保持一致,不要只改函数名不改调用方
  • 调试加载结果可写 soup.html / pv.md(见 dev.py)
  • 修改主题与题干模板:qparse/render_option/
  • 修改 DOCX 后处理:qparse/docx_render/write_buffer.py

许可证

内部备课工具,按团队约定使用。

Metadata

Release files for qparse 0.1.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for qparse 0.1.2
File Size Uploaded
qparse-0.1.2.tar.gz 78.1 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for qparse 0.1.2
File Interpreter ABI Platform
qparse-0.1.2-py3-none-any.whl Python 3 none any Details

Total release size: 160.5 kB

Release files / qparse-0.1.2.tar.gz

Download URL qparse-0.1.2.tar.gz
Size 78.1 kB
Tags Source
SHA-256 checksum
How to use checksums
ca2fdc066b2d4cfe007dbb6b62a1719a91ea0a01f7186b47a05e5337bc8bb994
BLAKE2b-256 checksum
How to use checksums
6393e10acd0fe2497ee37ed478ce4e5a10676cefd11c0cfeae402af30518e205
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.10.18

Release files / qparse-0.1.2-py3-none-any.whl

Download URL qparse-0.1.2-py3-none-any.whl
Size 82.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
a0cbf5fc30f6cf07187946de55a0762f50a3b6ddbdf54fd6558c1fa48fa8e88c
BLAKE2b-256 checksum
How to use checksums
8628fbccd451c093cce0c052a1ba67e58e11fcb66b94b6f5a3e1e0de425c49a3
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.10.18

Release history Release notifications | RSS feed

0.1.13

2 release files

0.1.12

2 release files

0.1.11

2 release files

0.1.7

2 release files

0.1.6

2 release files

0.1.5

2 release files

0.1.4

2 release files

0.1.3

2 release files

This release

0.1.2 This release

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page