Skip to main content

A powerful block-based markup language parser and query API, fully compatible with Markdown

Project description

BlockMD 查询 API

一个功能强大的 BlockMD 文档链式查询 API,支持过滤、排序和多种视图格式。

特性

链式 API - 流畅的方法链式调用,支持复杂查询
文件/目录加载 - 从单个文件或整个目录加载
灵活过滤 - 按属性、层级、内容、自定义条件过滤
Lambda 支持 - 使用 lambda 函数进行复杂条件判断
排序功能 - 按字段或自定义 lambda 函数排序
多种视图 - 树形、表格和列表输出格式
字段提取 - 提取特定字段为字典

安装

# 克隆仓库
git clone <repo-url>
cd wesleysbmd

# 运行测试
python tests/test_query_builder.py

快速开始

from query import query

# 加载并查询 BlockMD 文件
results = (query()
    .from_path('docs/spec.bmd')
    .where(level=lambda l: l >= 2)
    .contains('TODO')
    .order_by('title')
    .view('table')
)

print(results)

API 参考

加载数据

from_path(path: str | Path) -> QueryBuilder

从文件或目录加载区块。

# 加载单个文件
query().from_path('document.bmd')

# 加载目录中所有 .bmd 文件
query().from_path('docs/')

from_blocks(blocks: List[Block]) -> QueryBuilder

从现有 Block 对象初始化。

from parser import parse_blockmd

blocks = parse_blockmd(text)
query().from_blocks(blocks)

过滤

where(**conditions) -> QueryBuilder

按属性条件过滤区块。

# 精确匹配
query().where(status='done', level=2)

# Lambda 函数
query().where(level=lambda l: l >= 2)

# 多个值
query().where(status=['todo', 'doing'])

# 特殊字段: title, level
query().where(title='Introduction')

has_property(*keys: str) -> QueryBuilder

过滤具有指定属性的区块。

# 单个属性
query().has_property('status')

# 多个属性 (AND)
query().has_property('status', 'priority')

contains(keyword: str, case_sensitive: bool = False) -> QueryBuilder

过滤内容包含关键词的区块。

# 不区分大小写 (默认)
query().contains('TODO')

# 区分大小写
query().contains('FIXME', case_sensitive=True)

filter(predicate: Callable[[Block], bool]) -> QueryBuilder

使用自定义条件函数过滤。

# 有子节点的区块
query().filter(lambda b: len(b.children) > 0)

# 叶子节点
query().filter(lambda b: b.is_leaf())

# 长内容
query().filter(lambda b: len(b.get_content_text()) > 100)

排序

order_by(key: str | Callable, reverse: bool = False) -> QueryBuilder

按字段或函数对区块排序。

# 按字段名排序
query().order_by('title')
query().order_by('level', reverse=True)

# 按属性排序
query().order_by('priority')

# 按 lambda 排序
query().order_by(lambda b: len(b.title))
query().order_by(lambda b: b.get_depth())

可用字段名:

  • title - 区块标题
  • level - 标题层级 (1-6)
  • depth - 树深度
  • 任何属性键

限制

limit(count: int) -> QueryBuilder

限制结果数量。

# 获取前 10 个结果
query().limit(10)

# 按优先级排序取前 5 个
query().order_by('priority').limit(5)

输出

view(format: 'tree' | 'table' | 'list', fields: List[str] = None) -> str

格式化结果以供显示。

# 树形视图 - 层级结构
print(query().view('tree'))
# └── Root [prop=value]
#     ├── Child A
#     └── Child B

# 表格视图 - 结构化列
print(query().view('table', fields=['title', 'level', 'status']))
# title | level | status
# ------+-------+--------
# Block | 2     | done

# 列表视图 - 简单编号列表
print(query().view('list', fields=['title', 'status']))
# 1. Block | status=done
# 2. Other | status=todo

select(*fields: str) -> List[dict]

提取特定字段为字典。

results = query().select('title', 'level', 'content')
# [
#   {'title': 'Intro', 'level': 1, 'content': '...'},
#   {'title': 'Overview', 'level': 2, 'content': '...'}
# ]

可用字段名:

  • title, level, content, path, depth
  • id (来自属性)
  • 任何属性键

execute() -> List[Block]

获取匹配的 Block 对象列表。

blocks = query().where(status='done').execute()
for block in blocks:
    print(block.title, block.level)

count() -> int

统计匹配的区块数量。

total = query().contains('TODO').count()
print(f"Found {total} TODOs")

示例

基础过滤

# 所有二级标题
query().from_path('doc.bmd').where(level=2)

# 已完成的任务
query().from_path('tasks.bmd').where(status='complete')

# 高优先级项目
query().from_path('tasks.bmd').where(priority='high')

Lambda 条件

# 二级或更高层级
query().where(level=lambda l: l >= 2)

# 多个状态值
query().where(status=['todo', 'doing'])

# 复杂条件
query().filter(lambda b: 
    b.level <= 3 and 
    len(b.children) > 0 and
    'TODO' in b.get_content_text()
)

内容搜索

# 查找所有 TODOs
query().contains('TODO')

# 查找 FIXMEs (区分大小写)
query().contains('FIXME', case_sensitive=True)

# 提及 "database" 的区块
query().contains('database').where(level=2)

排序

# 按标题字母顺序
query().order_by('title')

# 按深度 (最深优先)
query().order_by('depth', reverse=True)

# 按内容长度
query().order_by(lambda b: len(b.get_content_text()))

# 按子节点数量
query().order_by(lambda b: len(b.children), reverse=True)

复杂链式调用

# 查找 2 级以上未完成的高优先级任务
results = (query()
    .from_path('project/')
    .where(
        status='todo',
        priority='high',
        level=lambda l: l >= 2
    )
    .order_by('priority')
    .limit(10)
    .view('table', fields=['title', 'priority', 'status'])
)

# 搜索 TODOs,按层级过滤,按深度排序
results = (query()
    .from_path('docs/')
    .contains('TODO')
    .where(level=lambda l: 2 <= l <= 3)
    .order_by('depth')
    .view('tree')
)

# 获取有子节点的模块,按名称排序
modules = (query()
    .from_path('specs/')
    .where(type='module')
    .filter(lambda b: len(b.children) > 0)
    .order_by('title')
    .select('title', 'children_count')
)

视图格式

# 树形视图 - 查看层级结构
print(query()
    .from_path('project.bmd')
    .where(level=lambda l: l <= 2)
    .view('tree')
)

# 表格视图 - 结构化数据
print(query()
    .from_path('tasks.bmd')
    .where(status='todo')
    .view('table', fields=['title', 'priority', 'status'])
)

# 列表视图 - 简单输出
print(query()
    .from_path('docs.bmd')
    .has_property('section')
    .view('list', fields=['title', 'section'])
)

统计

# 按状态统计
q = query().from_path('tasks.bmd')
print(f"总数: {q.count()}")
print(f"已完成: {q.where(status='done').count()}")
print(f"待办: {q.where(status='todo').count()}")

# 按层级统计区块
for level in range(1, 4):
    count = q.where(level=level).count()
    print(f"层级 {level}: {count} 个区块")

高级用法

从多个源加载

# 加载多个文件
q = query()
q.from_path('specs/api.bmd')
q.from_path('specs/database.bmd')
results = q.where(type='function').execute()

# 加载整个目录
q = query().from_path('docs/')  # 递归 *.bmd

自定义过滤器

# 标题较长的区块
query().filter(lambda b: len(b.title) > 50)

# 特定深度的区块
query().filter(lambda b: b.get_depth() == 2)

# 有特定祖先的区块
def has_ancestor(block, title):
    current = block.parent
    while current:
        if current.title == title:
            return True
        current = current.parent
    return False

query().filter(lambda b: has_ancestor(b, 'API'))

属性继承

BlockMD 支持使用 key* 语法的属性继承:

# Parent
`status`: active

## Child
`status*`: working

结果: Child 的 status="active/working"

查询继承的属性:

# 查找具有继承状态的区块
query().filter(lambda b: '/' in b.get_property('status', ''))

运行测试

# 测试 QueryBuilder API
python tests/test_query_builder.py

# 运行所有解析器测试
python tests/test_parser.py

示例

查看 examples/query_demo.py 获取所有特性的完整示例:

python examples/query_demo.py

API 使用

# 链式、流畅的接口
query()
    .from_path('docs/')
    .where(level=lambda l: l >= 2)
    .contains('TODO')
    .order_by('title')
    .view('table')

BlockMD 格式说明

什么是 BlockMD?

BlockMD 是一种与 Markdown 完全兼容的块状标记语言,为标准 Markdown 文件增加了结构化和元数据功能。

基本语法

# 区块标题
`property`: value
`status`: active

区块内容可以包含任何标准 Markdown 格式。

## 子区块
`status*`: working

子区块继承父区块的属性。

核心概念

  • 区块(Block):由 Markdown 标题(### 等)定义
  • 层级(Level):标题的 # 数量(1-6)决定嵌套层级
  • 属性(Properties)`key`: value 格式的键值对元数据
  • 继承(Inheritance)`key*`: value 语法从父区块继承属性
  • 内容(Content):标准 Markdown 文本

许可证

MIT

贡献

欢迎贡献!提交 PR 前请确保测试通过。

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

wesleysbmd-0.1.3.tar.gz (23.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

wesleysbmd-0.1.3-py3-none-any.whl (14.7 kB view details)

Uploaded Python 3

File details

Details for the file wesleysbmd-0.1.3.tar.gz.

File metadata

  • Download URL: wesleysbmd-0.1.3.tar.gz
  • Upload date:
  • Size: 23.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.7.8

File hashes

Hashes for wesleysbmd-0.1.3.tar.gz
Algorithm Hash digest
SHA256 adcf32d1f9ad7306151a52f631aa2d385e027c4ae784e1c77d2607a6ec17531d
MD5 4a04bf046c53ec3acf8af814957a4f93
BLAKE2b-256 8da37d548450fec4b16aab549713e9131a92c3fcaad6a07d96e20d71db68b804

See more details on using hashes here.

File details

Details for the file wesleysbmd-0.1.3-py3-none-any.whl.

File metadata

  • Download URL: wesleysbmd-0.1.3-py3-none-any.whl
  • Upload date:
  • Size: 14.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.7.8

File hashes

Hashes for wesleysbmd-0.1.3-py3-none-any.whl
Algorithm Hash digest
SHA256 e4f1aaac00307e51a4160a9f2485e9f7cf5e3e753d89f760e388add43891206c
MD5 8fa680e35f52f31152456125d627907e
BLAKE2b-256 59c4f559881b55aa0502e6e5b30b6ebe9c28d12124f4980b30ea7cdebbd10b3f

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page