SHLS(Sebis Hierarchical List Structure)书写结构化数据时不用引号、括号、冒号,也不重复键:每个节只列出一次键,下面的记录只列出值。SHLS 编辑器显示代码,并在旁边显示每个节的键块和记录。可直接修改值、键和记录,按行查看问题,与 JSON、YAML 和 CSV 互相转换,并查看 SHLS 相比 JSON 节省了多少 Token。
一切都在你的浏览器中运行。文档不会上传,无需注册,也没有广告。
一个节以其名称开始。其键块列出各个键,缩进一个空格;嵌套列表的键再深一级。恰好一个空行之后是记录:按键的顺序每行一个值。嵌套列表单独占一行(其键,或占位符 PH),其记录再深一级。所有值都是文本,是否转换为数字或日期由读取它们的程序决定。
Product
Name
Price
Smartphone A1
599.99
Laptop B2
1299.99
Company
Name
Location
Country
City
TechCorp
PH
USA
San Francisco
同样的数据写成 JSON 时,每条记录都要重复每个键,还需要引号、括号和冒号。SHLS 专为本地和云端 AI 模型设计,在那里每个 Token 都很重要。SHLS by Sebastian Grünwald:格式、规则以及参考实现 SHLSDecoder 和 SHLSEncoder(Python)都在 GitHub 上的 SHLS 仓库中。
左侧是高亮的 SHLS:节、键、值、嵌套层级和 PH 占位符。中间是每个节的键块及其记录,键作为标签显示。点击会跳转到代码,代码光标会标出其记录。
修改值、键和节名称;添加、复制、移动和删除记录与键。记录跟随其键块:新键在每条记录中得到“-”。每项都可一步撤销。
编辑器读取 SHLS 的方式与 SHLSDecoder 完全相同,并列出读取结果与外观不同之处:记录少了或多了一个值、缩进、键块后的空行、重复的键。
“转换”标签页会统计你的 SHLS 以及同样数据的 JSON 的近似 Token 数,节省多少一目了然。
与 JSON 互相转换(与 SHLSDecoder 和 SHLSEncoder 完全一致),以及 YAML、CSV(一个节作为表格)和 JSON Lines。JSON、YAML、CSV 和 JSON Lines 文件会以 SHLS 打开。
在浏览器中保存任意数量的文档,各有自己的撤销历史,并可全部打包成 ZIP 下载。
任何 https 页面(以及 localhost)都可以用 <iframe> 和 ?embed=1 嵌入编辑器,无需注册,无需密钥。嵌入后,编辑器会隐藏这段文字并显示“保存”按钮。有两种方式传入和取出文档。
src= 打开一个文件(你的服务器必须允许 CORS),webhook= 让“保存”(Ctrl+S)把文档发送到该地址。加上 &token=… 可发送 Authorization: Bearer … 请求头,加上 &auto 则每次更改后都会保存。
<iframe src="https://shls.giit.ch/?embed=1&src=https://your-site.com/data/products.shls&webhook=https://your-site.com/save.php"
allow="clipboard-write" style="width:100%;height:800px;border:0"></iframe>
Webhook 会收到一个带 JSON 的 POST 请求 { editor: "shls", event: "save", id, name, content, updated };content 是字符串形式的文档。一个保存它的简短 PHP 脚本:
<?php
header('Access-Control-Allow-Origin: https://shls.giit.ch');
header('Access-Control-Allow-Headers: Content-Type, Authorization');
header('Access-Control-Allow-Methods: POST, OPTIONS');
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') exit;
if (($_SERVER['HTTP_AUTHORIZATION'] ?? '') !== 'Bearer SECRET') { http_response_code(403); exit; }
$d = json_decode(file_get_contents('php://input'), true);
$name = preg_replace('/[^\w\- ]/u', '_', $d['name']);
file_put_contents(__DIR__ . "/data/$name.shls", $d['content']);
echo '{"ok":true}';
编辑器发送 shlseditor:ready,你的页面以 shlseditor:load 回应,编辑器报告 shlseditor:loaded,有实际编辑时发送 shlseditor:change,用户保存时发送 shlseditor:save。你的页面可以发送 shlseditor:get(获取当前状态)或 shlseditor:save(相当于点击“保存”)。这样保存就通过你自己的登录和会话进行。
<iframe id="ed" src="https://shls.giit.ch/?embed=1" allow="clipboard-write" style="width:100%;height:800px;border:0"></iframe>
<script>
const ed = document.getElementById('ed');
const ORIGIN = 'https://shls.giit.ch';
addEventListener('message', async e => {
if (e.source !== ed.contentWindow || e.origin !== ORIGIN) return;
const m = e.data;
if (m.type === 'shlseditor:ready') { // 编辑器已就绪:把文档交给它
ed.contentWindow.postMessage({
type: 'shlseditor:load',
name: 'Products',
content: await (await fetch('/data/products.shls')).text()
}, ORIGIN);
}
if (m.type === 'shlseditor:change') document.title = '● not saved'; // 一次实际编辑
if (m.type === 'shlseditor:save') { // 用户点击了“保存”
await fetch('/api/save', { method: 'POST', headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name: m.name, content: m.content }) });
document.title = 'Saved';
}
});
// 你自己页面上的保存按钮:回应以 shlseditor:save 返回
function saveNow() { ed.contentWindow.postMessage({ type: 'shlseditor:get' }, ORIGIN); }
</script>
页面内的 AI 助手:在框架中同样可用。在 iframe 上设置 allow="clipboard-write" 后,“复制提示词”会直接使用剪贴板(否则编辑器会退回旧的复制命令,或显示提示词供手动复制)。AI 发送的链接无法到达另一个网站中的编辑器,因此编辑器会提示 AI 和用户把 AI 的完整回答粘贴到编辑器中,或在单独的窗口中打开编辑器。
window.open("https://shls.giit.ch/?embed=window", "shlseditor-17") 会在单独的窗口中打开完整的编辑器,并通过 window.opener 使用相同的消息。AI 的链接可以到达那里。shlseditor:load 还可以带上 context: { host, title, rules }(AI 提示词随后会说明文档属于哪里,并遵循你的规则),以及 hook: { url, token },即仅用于此文档、从不保存的 Webhook。关闭有未保存更改的窗口时会发送 shlseditor:closing。
向编辑器提供你自己的提示词、你网站上的一个地址和本次编辑器会话的密钥。AI 对话框随后会显示“已连接到”你的网站、你告诉 AI 的内容,以及修改当前文档或新建一个文档的选项;复制提示词会把这些都组合起来。AI 带着密钥把结果发送到你的服务器,你的页面再在编辑器中打开它;新文档会单独打开,并保留在用户的浏览器中。每个编辑器会话一个密钥:编辑器打开期间有效,只有在没有密钥时,编辑器才会用 shlseditor:key-request 请求。编辑器自己从不发送密钥,也从不保存它;地址必须是你自己主机或其子域名上的 https 地址。
const key = async () => (await fetch('/api/ai-key.php?doc=17')).json(); // 每个编辑器会话一个密钥
const k = await key();
ed.contentWindow.postMessage({ type: 'shlseditor:load', name: 'Products', content, ai: {
label: 'My Site', prompt: 'Keep every key. Only add records.',
endpoint: 'https://your-site.com/api/ai-result.php', key: k.key } }, ORIGIN);
// 记住 shlseditor:loaded 中的 id,忽略 id 不同的 change/save/closing
// 仅在编辑器没有密钥时:
if (m.type === 'shlseditor:key-request') { const k = await key(); ed.contentWindow.postMessage({ type: 'shlseditor:ai', key: k.key }, ORIGIN); }
// 编辑器打开期间,每分钟通知你的服务器;关闭编辑器或页面会使密钥作废
setInterval(() => fetch('/api/ai-key.php?alive=' + k.key.slice(0, 8)), 60000);
// 你的服务器有了结果(轮询、SSE …):target 为 "current" 或 "new"
ed.contentWindow.postMessage({ type: 'shlseditor:load', name: 'Products', content: draft, from: 'ai', target }, ORIGIN);
密钥至少使用 128 位随机数,只保存其哈希值,将每个密钥绑定到已登录用户、文档和本次编辑器会话,每个会话一个,仅在你的页面报告会话仍打开时有效,并在编辑器或页面关闭时作废。
完整协议见 llms.txt,把它交给 AI,AI 就能为你的系统建立连接。JSON 编辑器的用法相同,前缀为 jsoneditor:,见 json.giit.ch。
SHLS(Sebis Hierarchical List Structure)是 Sebastian Grünwald 设计的结构化数据文本格式。每个节在键块中只列出一次键;下面的记录只列出值,每行一个,缩进表示嵌套。不用引号、括号、冒号,也不重复键,同样的数据所需的 Token 比 JSON 少得多,因此很适合 AI 模型。
不会。编辑器完全在你的浏览器中运行。你的文档绝不会发送到服务器,除非你自己设置了指向自己服务器的 Webhook。
是的。编辑器读写 SHLS 的方式与 SHLS 仓库中的 SHLSDecoder 和 SHLSEncoder 完全相同,“转换”标签页中的 JSON 就是这些 Python 类给出的数据。如果它们读出的文档与外观不同(记录少了一个值、空行中有空格),编辑器会将其作为问题连同行号列出。
可以。在中间区域点击值、键或节名称,输入后按 Enter。记录上方的按钮可添加、复制、移动和删除记录与键;添加或删除键时,该节的每条记录都会相应得到或失去其值。每次更改都可一步撤销。
转换标签页会统计你的文档作为 SHLS 以及同样数据作为 JSON 的近似 Token 数。对于记录表格,SHLS 通常只需缩进 JSON 一半不到的 Token,因为键只写一次。
能。打开 .json、.yaml、.csv 或 .jsonl 文件,它就会按 SHLSEncoder 的写法变为 SHLS;编辑器会说明 SHLS 无法保留的内容(空值、含换行的值)。“转换”标签页和“导出”可写出 JSON、YAML、CSV、JSON Lines 和纯文本。
能,任何 AI 都可以:ChatGPT、Claude、Gemini、Copilot 或你编程工具中的 AI。点击“AI 助手”,再点击“复制提示词”:提示词会说明 SHLS,因此任何 AI 都能写出有效的 SHLS。AI 会回复一个链接;点击它,文档就会出现在你的编辑器中。“撤销”可撤回每一处更改。
不收费。编辑器免费,没有广告,无需注册。