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.0.tar.gz (23.8 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.0-py3-none-any.whl (6.3 kB view details)

Uploaded Python 3

File details

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

File metadata

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

File hashes

Hashes for wesleysbmd-0.1.0.tar.gz
Algorithm Hash digest
SHA256 37cef22c1bcc6182a315c5aa9330c8d522d00c77befaf24fdaa428d81b042351
MD5 76b11e3c31debc9c6b87648fc52531af
BLAKE2b-256 7e7b68fecee8f39af254951124e6669cfe56c50fd9ad89bc56eed892c52e3c0a

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for wesleysbmd-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 5586aa115bbc485b378fd7c8a9cc58a2ce28ff264b1edd52ec77735ae9138bb2
MD5 f189f9994ac7783a36e1f1af83ddff85
BLAKE2b-256 8beb6b68f266cc70ef4db0e20ca2ca1724d0696e4b1745798578357aaa9d4c6b

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