豫言 / 豫言操作系统网页文树 @ 0.3.0

当前网页的受限文树构建、句柄管理与同源只读资源接口。

源码浏览已生成;不能解析的文件以纯文本展示,不表示通过类型检查。

规范.汉语.md

# 网页文树接口规范 0.3.0

这个能力组供在浏览器里运行的豫言应用构建当前页面。应用以 ID 获取已有节点,或按白册创建新节点,再写纯文本、受限属性并组合成树;也可以一次调用建出整棵树。句柄目前投影为字符串,语义上是当前应用实例内的资源编号;应用不得自行构造或跨实例保存。适配层必须拒绝未知标签、未知属性、可执行链接和无效句柄。

0.3.0 相对 0.2.0 **只增函数与标签**(旧函数签名与语义不变):选择器查询与节点读回(`查询页面节点`、`读取页面节点标签/属性/文字/父级`、`查找最近页面祖先`、`页面节点匹配选择器`)、子树导出(`读取页面节点树`)、`替换页面节点`、`移除页面节点属性`、`设置页面节点超文本`;标签白册增 `em`、`i`、`kbd`、`sup`、`sub`、`blockquote`、`hr`、`dl`、`dt`、`dd`(`hr` 是空元素)。它们让应用能对**已经存在于页面里的服务端渲染内容**(例如包阅读页)做后加工,而不必写 JavaScript;见[前端补全计划](../../豫言操作系统/文档/前端补全计划.汉语.md)。

0.2.0 相对 0.1.0:扩充标签与属性白册;新增一次建树(`构建页面节点树`)、插入/替换/移除/释放节点、追加文字、设置 iframe 地址、装入页面模板与读取页面网址;**明确句柄的释放规则并提供自动释放**。0.1.0 的函数签名全部不变。

## 句柄与释放规则

宿主为每个应用实例维护一张句柄表,**上限 4096 项**。下列函数会产生句柄:`取得页面节点`、`新建页面节点`、`构建页面节点树`,以及 0.3.0 的 `查询页面节点`(每个匹配元素一个)、`读取页面节点父级`、`查找最近页面祖先`。句柄表满时,产生句柄的函数抛事故(“页面节点句柄达到上限(4096)……”);因此应用必须遵守:

1. **不再需要的句柄要用 `释放页面节点` 释放。** 释放只是让应用放弃这个编号,不影响节点本身:节点若已在文档里,它仍在文档里。
2. 同一个元素重复 `取得页面节点` 得到同一个句柄(不额外占位);释放后再取得会得到新的句柄编号。
3. **自动释放**(子树随根管理):`移除页面节点`、`清空页面子节点`、`替换页面子节点` 移除的子树里,**所有节点的句柄**(含被移除节点本身)由宿主同步释放,之后再使用这些句柄会抛“页面节点句柄无效”。`装入页面模板` 替换目标元素原有子节点时同理。
4. **一次建树只占一个句柄**:`构建页面节点树` 返回根节点一个句柄;树内其余节点没有句柄。若之后要单独操作树内某个节点,请在描述里给它一个 `id` 属性,再用 `取得页面节点`。
5. `新建页面节点` 与 `构建页面节点树` 造出的节点在被插入文档之前不属于文档;句柄被释放而节点从未插入,则节点随之被丢弃。

推荐用法:动态区域用 `构建页面节点树` 一次建出一行(一个句柄),`插入页面子节点前` 或 `添加页面子节点` 放进容器,立刻 `释放页面节点`;容器本身在启动时 `取得页面节点` 一次并持有;整个区域重绘时用 `清空页面子节点` 或 `替换页面子节点`,旧行的句柄随之自动释放。

## 失败语义

本组所有失败都属于**违规调用或平台故障**,一律抛豫言事故(可被应用捕获),事故消息为中文并保留原因:元素不存在、句柄无效或不是节点、标签或属性不在白册、链接不合规、层级违规(把祖先放进后代)、参照节点不是父节点的子节点、限额超出、句柄表满、网络与编码错误。宿主不得把失败当作成功,也不得让宿主异常越过豫言边界而使应用无法捕获。

## 白册

**标签**:`a`、`span`、`small`、`b`、`strong`、`br`、`h1`、`h2`、`h3`、`h4`、`h5`、`p`、`section`、`div`、`article`、`nav`、`button`、`table`、`thead`、`tbody`、`tr`、`th`、`td`、`pre`、`code`、`time`、`ul`、`ol`、`li`、`label`、`select`、`option`、`form`、`input`、`textarea`、`details`、`summary`,以及 0.3.0 增加的 `em`、`i`、`kbd`、`sup`、`sub`、`blockquote`、`hr`、`dl`、`dt`、`dd`。`br`、`input`、`hr` 是空元素,不能带文字或子节点。`script`、`style`、`iframe`、`object`、`embed`、`link`、`meta`、`base`、`img`、`svg`、`video`、`dialog`、`template` 等不在白册内。标签名区分大小写,只接受上列小写形式。

**属性**:与[网页界面接口规范](../网页界面/规范.汉语.md)“属性”一节是**同一张表**——`class role type title hidden disabled readonly placeholder tabindex datetime maxlength rows colspan rowspan for value id checked selected open href target aria-* data-*`;`data-yy-` 前缀保留给宿主;`target=_blank` 时宿主强制 `rel=noopener noreferrer`;`href` 只允许 `/路径`(不含 `//`)、`#锚`、`https://`、`http://`,`http:` 只对 `a[href]` 放行;`style`、`src`、`srcdoc`、`name`、`action` 与所有 `on*` 一律拒绝。

**危险元素不给句柄**:`取得页面节点` 对 `script`、`style`、`iframe`、`object`、`embed`、`link`、`meta`、`base` 等元素报错,避免应用改写它们的内容或属性。

## 函数

### 取得、创建、修改(0.1.0 起)

- `取得页面节点 : 字符串(ID) → 字符串(句柄)`:按 ID 取当前页面里已有的节点。
- `新建页面节点 : 字符串(标签) → 字符串(文字) → 字符串(类名) → 字符串(句柄)`:创建白册内的元素,文字为纯文本(空字符串表示不设),类名规则同 `设置节点类名`(空字符串表示不设)。文字至多 8 MiB。
- `设置页面节点文字 : 字符串 → 字符串 → 有`:整体设置节点的文字内容(`textContent`)。
- `设置页面节点属性 : 字符串 → 字符串 → 字符串 → 有`:按白册设置属性;布尔属性值用 `""`、`"true"`、`"false"`。
- `添加页面子节点 : 字符串(父) → 字符串(子) → 有`:把子节点添加到父节点末尾;子节点已在文档中则是移动。
- `清空页面子节点 : 字符串 → 有`:移除节点的所有子节点,并释放被移除子树里所有节点的句柄(**0.2.0 新增的释放规则**)。
- `设置页面标题 : 字符串 → 有`、`读取页面查询参数 : 字符串 → 字符串`、`读取页面资源文字 : 字符串 → 字符串`:同 0.1.0。读取资源只接受以单斜杠开头的站内路径,不得含反斜杠;宿主核对解析后的 origin,禁止重定向,仅接受 HTTP 200,并逐块限制正文为 2 MiB,按严格 UTF-8 解码。

### 一次建树

`构建页面节点树 : 字符串(描述 JSON) → 字符串(根节点句柄)`。描述是 JSON 对象:

```json
{"标签":"article","类":"event event-command","属性":{"data-yy":"打开:7","id":"行7"},
 "文字":"首段文字","子":[{"标签":"p","文字":"段落"},"裸文字",{"标签":"ul","子":[{"标签":"li","文字":"一"}]}]}
```

- `标签` 必填,须在白册内;`类`、`属性`、`文字`、`子` 可省。`属性` 的值可以是文字、数字或布尔(数字转十进制文字,布尔转 `true`/`false`)。
- `文字` 是节点的第一个子节点(文本节点);`子` 里的项可以是对象(子元素)或字符串(文本节点)。
- 未知字段、类型不对、空元素带文字或子节点、`id` 在树内重复或与文档已有 ID 冲突,都报错并指出出错位置(如 `根.子[0].子[1]`)。
- 限额:深度至多 32(根为第 1 层)、节点(元素与文本节点)至多 2000、文字总量至多 1 MiB(UTF-8 字节)、属性名值总字符数至多 1 MiB、描述 JSON 至多 2 MiB(UTF-16 码元)。
- 树是**整体原子**地建出:任何一步失败都不留下任何节点与句柄。建好的树在被插入文档之前不属于文档。

### 组合

- `插入页面子节点前 : 字符串(父) → 字符串(子) → 字符串(参照) → 有`:把子节点插入父节点中参照子节点之前;参照为空字符串表示追加到末尾;参照必须是父节点的子节点;子节点已在文档中是移动。
- `替换页面子节点 : 字符串(父) → (列于 字符串)(子们) → 有`:用给定的子节点列表整体替换父节点的所有子节点(至多 2000 项,不得重复);被替换掉的子树里所有句柄同时释放(仍在新列表里的节点不受影响);空列表等于清空。
- `移除页面节点 : 字符串 → 有`:把节点从其父节点移除,并释放该节点及其子树内所有节点的句柄。
- `释放页面节点 : 字符串 → 有`:释放一个句柄;句柄无效时抛事故。
- `追加页面节点文字 : 字符串 → 字符串 → 有`:在节点末尾追加纯文本,用于流式输出。末尾已是文本节点时并入它(连续追加不产生碎片节点),否则新建文本节点。单次至多 8 MiB,追加后该文本节点至多 8 MiB;空元素报错。

### 框架与模板

- `设置页面框架地址 : 字符串(iframe 的 ID) → 字符串(网址) → 有`:改页面里**已有** iframe 的 `src`。iframe 必须由页面(HTML)声明 `sandbox` 属性——应用不能创建 iframe,也不能修改 `sandbox`、`allow`、`referrerpolicy` 等属性(不在白册内)。地址只允许:以 `/` 开头但不以 `//` 开头的**同源路径**,或 **`https://` 网址,且其 origin 是页面在该 iframe 的 `data-yy-frame-origins` 属性(空格分隔的 origin 列表)里声明的**(与页面同源的 https 网址亦可)。含空白、控制字符、反斜杠或超过 2048 个字符的地址拒绝;空字符串表示移除 `src`。
- `装入页面模板 : 字符串(资源路径) → 字符串(模板内元素 ID) → 字符串(目标 ID) → 有`:用与 `读取页面资源文字` 相同的规则读取同源 HTML 模板,在模板里按 ID 选出一个元素,复制后**清洗**,再作为目标元素的唯一子节点装入(目标原有子节点被移除,其子树内的句柄同时释放)。清洗:剔除 `script`、`style`、`iframe`、`object`、`embed`、`link`、`meta`、`base`、`frame`、`frameset`、`applet`、`template` 元素,剔除所有 `on*`、`srcdoc`、`formaction` 属性,剔除 `javascript:` 与 `vbscript:` 链接,`target=_blank` 的链接强制 `rel=noopener noreferrer`;模板里没有该 ID 时抛事故。此函数会挂起等待网络。
- `读取页面网址 : 有 → 字符串`:当前页面的完整 URL(含查询与片段),用于构造给其他能力包使用的绝对网址。

### 选择器查询与节点读回(0.3.0)

这一组让应用**读到**页面里已有的内容(包括没有 ID 的元素)并加以改造。所有“选择器”参数是 CSS 选择器(选择器列表亦可,至多 512 个字符),语法错误抛事故;所有“节点”参数是上文的句柄,必须是元素。

- `查询页面节点 : 字符串(根) → 字符串(选择器) → 字符串(JSON 数组)`:等价于 `querySelectorAll`。`根` 是节点句柄,**空字符串表示整个文档**;根是 `<template>` 元素时在它的 `content` 里查询(用来读页面里放着的数据模板)。返回 JSON 数组文字,每项是一个元素句柄字符串,按文档顺序,同一元素得同一句柄。危险元素(`script`、`style`、`iframe` 等)不出现在结果里;匹配超过 1024 个元素、或句柄表剩余不足时抛事故(应先收窄选择器、并及时释放句柄)。
- `读取页面节点标签 : 字符串 → 字符串`:小写标签名。
- `读取页面节点属性 : 字符串(节点) → 字符串(名称) → (爻 合 字符串)`:属性的原样文字,返回(存在与否,值);名称与限制同网页界面包的 `读取节点属性`。
- `读取页面节点文字 : 字符串 → 字符串`:`textContent`,按 UTF-8 至多 8 MiB。
- `读取页面节点父级 : 字符串 → 字符串`:父元素的句柄;没有父元素(含节点在 `<template>` 内容里)或父是危险元素时返回空字符串。
- `查找最近页面祖先 : 字符串(节点) → 字符串(选择器) → 字符串`:等价于 `closest`(含自身),返回句柄,没有则空字符串。
- `页面节点匹配选择器 : 字符串 → 字符串 → 爻`:等价于 `matches`。
- `读取页面节点树 : 字符串(节点) → 整数(深度上限) → 字符串(JSON)`:把元素及其子树导出为描述文字,**形状与 `构建页面节点树` 的输入相同**——`{"标签","类","属性","子"}`,文字节点是 `子` 里的字符串,节点之间的空白文字照原样保留;只导出白册内的属性(`class` 写在 `类` 里,`on*`、`style`、`src` 等被略去);危险元素与 `<template>` 子树被略去;深度上限 1 至 32,超过所给上限、节点超过 2000 或文字超过 1 MiB 时抛事故。导出的描述再用 `构建页面节点树` 重建时仍按白册校验:标签不在白册、`id` 与文档中已有的重复、链接不合规都会被拒,应用需要先改写(例如去掉 `id`)。典型用法:导出说明区的内容,在豫言里按文字偏移切分、改写后重建,再 `替换页面子节点`。
- `替换页面节点 : 字符串(旧) → 字符串(新) → 有`:`旧.replaceWith(新)`;`新` 可以是新建节点或已在文档里的节点(则是移动)。**旧节点及其子树的句柄不释放**,旧节点可以再放到别处——例如先把它替换成一个新建的链接,再 `添加页面子节点(链接, 旧)` 完成“给原节点包一层”。旧节点没有父节点、或把祖先放进后代时抛事故。
- `移除页面节点属性 : 字符串 → 字符串 → 有`:规则同网页界面包的 `移除节点属性`。
- `设置页面节点超文本 : 字符串(节点) → 字符串(HTML) → 有`:把 HTML 文字在惰性环境里解析,按白册**清洗并复制**后整体替换节点的子节点。标签与属性必须全在白册内,**不合规时抛事故并指出位置,不悄悄剔除**;注释被丢弃;文字至多 2 MiB、节点至多 5000、深度至多 32;被替换掉的旧子树里的句柄同时释放。用于装入豫言高亮器等**可信来源**产生的只含 `<span class>` 的片段;它不是通用的 `innerHTML`。

## 限额

| 项 | 限额 |
| --- | --- |
| 句柄表 | 每个应用实例 4096 项 |
| 一次建树 | 深度 ≤ 32;节点 ≤ 2000;文字 ≤ 1 MiB(UTF-8);属性总量 ≤ 1 MiB;描述 ≤ 2 MiB |
| `替换页面子节点` | ≤ 2000 项 |
| `查询页面节点` | 选择器 ≤ 512 字符;匹配 ≤ 1024 个元素 |
| `读取页面节点树` | 深度 ≤ 32;节点 ≤ 2000;文字 ≤ 1 MiB |
| `设置页面节点超文本` | HTML ≤ 2 MiB;节点 ≤ 5000;深度 ≤ 32 |
| 文字与追加 | 单次与单个文本节点 ≤ 8 MiB |
| 属性值 | ≤ 65536 个 UTF-16 码元 |
| 页面资源 | ≤ 2 MiB,仅同源 GET |

## 跨宿主一致性

- 白册、限额、释放规则与失败分类必须与本文一致;宿主可以更严,不可以更松。
- 句柄编号是不透明字符串,应用只能原样传回;宿主不得让已释放的句柄编号悄悄指向另一个节点(参考实现的编号在实例内单调递增、绝不复用)。
- `构建页面节点树` 在树内的 `id` 唯一性检查只在一次调用范围内;建好后插入文档时若与既有 ID 重复,后者行为按浏览器(`getElementById` 取文档顺序里的第一个),应用应保证 ID 唯一。

## 一致性样例

1. 建树 `{"标签":"div","子":[{"标签":"script"}]}`:抛事故,指出位置 `根.子[0]`,句柄表不增。
2. 建一棵 2 层的树并 `添加页面子节点` 到容器,再 `释放页面节点`(根):节点仍在文档中,句柄表回到原来的数量;循环 10000 次后句柄表仍为原数量。
3. 容器里有 3 行,各行及其子节点都拿过句柄;`清空页面子节点(容器)` 之后,这些句柄全部失效,容器的句柄仍有效。
4. `设置页面框架地址("网站画面", "https://evil.example/")`:iframe 的 `data-yy-frame-origins` 里没有该 origin,抛事故。
5. `装入页面模板` 装入的模板里含 `<script>` 与 `onclick`:装入后文档里没有脚本元素,元素上没有 `onclick`。
6. (0.3.0)页面有三个 `<a class="引用" href="/x">`:`查询页面节点("", ".引用")` 返回三个句柄;`读取页面节点属性(柄, "href")` 为(阳,“/x”);`读取页面节点父级(柄)` 是它们共同的父元素句柄;`查找最近页面祖先(柄, "section")` 找到外层 section。
7. (0.3.0)`<template id="资料"><a data-qualified="甲.乙" href="/a">甲</a></template>`:`查询页面节点(取得页面节点("资料"), "a[data-qualified]")` 得到模板内容里的那个 a(普通的文档查询看不到它)。
8. (0.3.0)`<code>ab<b class="k">cd</b></code>` 导出为 `{"标签":"code","子":["ab",{"标签":"b","类":"k","子":["cd"]}]}`;把它原样交给 `构建页面节点树` 得到等价的新树。
9. (0.3.0)`替换页面节点(旧, 新链接)` 之后 `添加页面子节点(新链接, 旧)`:旧节点仍有效,最终位置在新链接内、新链接在原处。
10. (0.3.0)`设置页面节点超文本(柄, "<span class=\"tok-k\">甲</span>乙")` 成功;含 `<script>`、`onclick` 或 `style` 的 HTML 抛事故,节点内容不变。

## 边界

本包不规定:选择器查询之外的节点遍历(`nextSibling`、`TreeWalker`、`Range` 等:请用 `读取页面节点树` 在豫言里遍历)、任意 CSS 与样式对象、`img` 与 `svg`、动态创建 iframe、自定义元素、Shadow DOM、MutationObserver、文档片段。没有文树的平台不提供这个包。

规范.文言.md

# 网页文树之约 0.3.0

此组供浏览器客建当前页。凭标识取旧节,或依白册签造新节,置纯文、受限属性而组之为树;亦可一呼而建全树。柄今投为字符串,其义惟本客器之资源号;客毋自造,毋跨实例久藏。适配须拒未许之签、属性、可执行址及坏柄。

零点三点零较零点二点零**惟增术与签**(旧术之签与义不易):选择器之查询与节点之读回(查询页面节点、读取页面节点标签、属性、文字、父级、查找最近页面祖先、页面节点匹配选择器)、子树之导出(读取页面节点树)、替换页面节点、移除页面节点属性、设置页面节点超文本;签之白册增 em、i、kbd、sup、sub、blockquote、hr、dl、dt、dd(hr 为空元素)。此诸术使客能对**已在页中之服务端所渲之内容**(如包阅读页)作后加工,而不必书 JavaScript;见[前端补全计划](../../豫言操作系统/文档/前端补全计划.汉语.md)。

零点二点零较零点一点零:广签与属性之白册;增一次建树(构建页面节点树)、插入、替换、移除、释放节点、追加文字、改 iframe 之址、装入页面模板与读取页面网址;**明柄之释放规则并设自动释放**。零点一点零诸术之签皆不易。

## 柄与释放之规

宿主为每客器立一柄表,**上限四千零九十六项**。下列术生柄:取得页面节点、新建页面节点、构建页面节点树,及零点三点零之查询页面节点(每合者一柄)、读取页面节点父级、查找最近页面祖先。柄表满,则生柄之术发事故(“页面节点句柄达到上限(4096)……”)。故客须守:

1. **柄不复用者,以释放页面节点释之。** 释之者,客弃其号耳,不损节点:节点若已在文档,仍在文档。
2. 同一元素重取得,得同一柄(不另占位);释后再取,得新号。
3. **自动释放**(子树随根而管):移除页面节点、清空页面子节点、替换页面子节点所去之子树,其中**诸节点之柄**(含被移之节自身)由宿主同步释之,其后再用此等柄则发“页面节点句柄无效”。装入页面模板易目标元素之旧子节,亦同。
4. **一次建树惟占一柄**:构建页面节点树返根节点一柄;树中余节无柄。后欲独治树中某节,当于描述中予其 id 属性,再以取得页面节点取之。
5. 新建页面节点与构建页面节点树所造之节,未插入文档前不属文档;柄释而节未尝插入,则节随之而弃。

宜行之法:动态之区以构建页面节点树一次建一行(一柄),以插入页面子节点前或添加页面子节点置于容器,旋即释放页面节点;容器自身于起时取得页面节点一次而持之;全区重绘则以清空页面子节点或替换页面子节点,旧行之柄随之自释。

## 败之义

此组诸败,皆属违约之调用或平台之故,一律发豫言事故,客可捕之,事故之辞用华言而存其因:元素阙、柄无效或非节点、签或属性不在白册、链接不合、层级违约(以祖置于后代)、参照非父之子、限额逾越、柄表满、网络与编码之误。宿主不得以败为成,亦不得使宿主之异常越豫言之界而客不能捕。

## 白册

**签**:a、span、small、b、strong、br、h1、h2、h3、h4、h5、p、section、div、article、nav、button、table、thead、tbody、tr、th、td、pre、code、time、ul、ol、li、label、select、option、form、input、textarea、details、summary,及零点三点零所增之 em、i、kbd、sup、sub、blockquote、hr、dl、dt、dd。br、input、hr 为空元素,不得带文与子。script、style、iframe、object、embed、link、meta、base、img、svg、video、dialog、template 等不在白册。签名分大小写,惟受上列小写之形。

**属性**:与[网页界面之约](../网页界面/规范.文言.md)“属性”一节**同一表**——class、role、type、title、hidden、disabled、readonly、placeholder、tabindex、datetime、maxlength、rows、colspan、rowspan、for、value、id、checked、selected、open、href、target、aria-*、data-*;data-yy- 之前缀专留宿主;target 为 _blank 则宿主必并设 rel 为 noopener noreferrer;href 惟许斜杠径(不含双斜杠)、井号锚、https://、http://,http: 惟于 a 之 href 放行;style、src、srcdoc、name、action 与诸 on* 一概拒之。

**险元素不予柄**:取得页面节点于 script、style、iframe、object、embed、link、meta、base 等元素则报错,免客改其文与属性。

## 诸术

### 取、造、改(零点一点零起)

- 取得页面节点(标识):按标识取当前页中既有之节。
- 新建页面节点(签、文、类名):造白册内之元素,文为纯文(空文则不设),类名之律同设置节点类名(空文则不设);文至多八 MiB。
- 设置页面节点文字:尽易节点之文(textContent)。
- 设置页面节点属性:依白册设属性;布尔属性之值用空文、true、false。
- 添加页面子节点(父、子):以子附于父之末;子已在文档则为移。
- 清空页面子节点:去节点诸子,并释所去子树中诸节点之柄(**零点二点零新增之释放规**)。
- 设置页面标题、读取页面查询参数、读取页面资源文字:同零点一点零。读资源惟受单斜杠首之站内径,不得含反斜杠;宿主核析后之源,禁改址,答必二百,逐块限二 MiB,以严 UTF-8 解之。

### 一次建树

构建页面节点树(描述癸象文)返根节点之柄。描述为癸象对象:

```json
{"标签":"article","类":"event event-command","属性":{"data-yy":"打开:7","id":"行7"},
 "文字":"首段文字","子":[{"标签":"p","文字":"段落"},"裸文字",{"标签":"ul","子":[{"标签":"li","文字":"一"}]}]}
```

- 标签必有,须在白册;类、属性、文字、子可省。属性之值可为文、数或布尔(数化十进制之文,布尔化 true 或 false)。
- 文字为节点之首子(文本节点);子中之项可为对象(子元素)或字符串(文本节点)。
- 未识之字段、类型不合、空元素带文或子、id 于树内重复或与文档既有者相冲,皆报错并指其位(如“根.子[0].子[1]”)。
- 限额:深至多三十二(根为第一层)、节(元素与文本节点)至多二千、文总量至多一 MiB(UTF-8 字节)、属性名值总字数至多一 MiB、描述癸象文至多二 MiB(UTF-16 码元)。
- 树**整体不可分**而建:任一步败,则无一节一柄留下。建成之树,未插入文档前不属文档。

### 组合

- 插入页面子节点前(父、子、参照):置子于父之参照子之前;参照为空文则置于末;参照须为父之子;子已在文档则为移。
- 替换页面子节点(父、子们):以所给子列尽易父之诸子(至多二千项,不得重复);被替之子树中诸柄同释(仍在新列者不受影响);空列即清空。
- 移除页面节点:自其父去此节,并释该节及其子树中诸节之柄。
- 释放页面节点:释一柄;柄无效则发事故。
- 追加页面节点文字:于节点末追加纯文,供流式输出。末已是文本节点则并入之(连续追加不生碎节),否则新造文本节点。单次至多八 MiB,追加后该文本节点至多八 MiB;空元素则报错。

### 框与模板

- 设置页面框架地址(iframe 之标识、网址):改页中**既有** iframe 之 src。iframe 须由页(HTML)自声明 sandbox——客不得造 iframe,亦不得改 sandbox、allow、referrerpolicy 等属性(不在白册)。址惟许:以斜杠起而不以双斜杠起之**同源径**,或 **https:// 址而其 origin 为页于该 iframe 之 data-yy-frame-origins 属性(空格隔之 origin 列)所声明者**(与页同源之 https 址亦可)。含空白、控制字、反斜杠或逾二千零四十八字之址拒之;空文则去 src。
- 装入页面模板(资源径、模板内元素标识、目标标识):依读取页面资源文字之律取同源 HTML 模板,于其中按标识选一元素,复制而**清洗**之,作为目标元素之独子装入(目标旧子去之,其子树中之柄同释)。清洗:去 script、style、iframe、object、embed、link、meta、base、frame、frameset、applet、template 元素,去诸 on*、srcdoc、formaction 属性,去 javascript: 与 vbscript: 之链,target 为 _blank 之链强设 rel 为 noopener noreferrer;模板无该标识则发事故。此术可挂起以待网络。
- 读取页面网址:当前页完整 URL(含查询与片段),供构造他能力包所用之绝对址。

### 选择器之查询与节点之读回(零点三点零)

此组使客得**读页中已有之物**(含无标识之元素)而加以改造。诸“选择器”参数乃 CSS 选择器(选择器之列亦可,至多五百一十二字),语法误则发事故;诸“节点”参数乃上文之柄,须为元素。

- 查询页面节点:字符串(根)、字符串(选择器),返字符串(癸象数组):等于 querySelectorAll。根乃节点之柄,**空文则谓整个文档**;根为 `<template>` 元素,则于其 content 内求之(以读页中所置之数据模板)。返癸象数组文,每项一元素之柄,依文档之序,同一元素得同一柄。险元素(script、style、iframe 等)不入其果;合者逾一千零二十四个,或柄表所余不足,则发事故(当先收窄选择器,并速释不用之柄)。
- 读取页面节点标签:字符串,返字符串:小写之签名。
- 读取页面节点属性:字符串(节点)、字符串(名),返(爻、字符串):属性之原文,返(存否,值);名与限同网页界面包之读取节点属性。
- 读取页面节点文字:字符串,返字符串:textContent,按 UTF-8 至多八 MiB。
- 读取页面节点父级:字符串,返字符串:父元素之柄;无父元素(含节点在 template 内容中)或父为险元素,则返空文。
- 查找最近页面祖先:字符串(节点)、字符串(选择器),返字符串:等于 closest(含自身),返柄,无则空文。
- 页面节点匹配选择器:字符串、字符串,返爻:等于 matches。
- 读取页面节点树:字符串(节点)、整数(深度上限),返字符串(癸象):导元素及其子树为描述文,**其形与构建页面节点树之入相同**——`{"标签","类","属性","子"}`,文节点为“子”中之字符串,节点间之空白文照原样留;惟导白册内之属性(class 书于“类”,on*、style、src 等略去);险元素与 `<template>` 之子树略去;深度之限一至三十二,逾所给之限、节逾二千或文逾一 MiB 则发事故。所导之描述,以构建页面节点树重建时仍依白册验之:签不在白册、id 与文档中已有者重、链接不合,皆见拒,客当先改写(如去其 id)。常法:导说明区之内容,于豫言中依文字偏移而切、而改,再重建,而后替换页面子节点。
- 替换页面节点:字符串(旧)、字符串(新),返有:`旧.replaceWith(新)`;新可为新造之节,亦可为文档中已有之节(是则为移)。**旧节点及其子树之柄不释**,旧节点可复置于他处——如先以新造之链替之,再添加页面子节点(链,旧),而成“为原节点包一层”。旧无父节点,或置祖于后代,则发事故。
- 移除页面节点属性:字符串、字符串,返有:律同网页界面包之移除节点属性。
- 设置页面节点超文本:字符串(节点)、字符串(HTML),返有:以 HTML 文于惰性之境解之,依白册**清洗而复制**,整体易节点之诸子。签与属性须尽在白册,**不合则发事故而指其位,不默剔**;注释弃之;文至多二 MiB、节至多五千、深至多三十二;被易之旧子树中之柄同释。用于装入豫言高亮器等**可信来源**所生之仅含 `<span class>` 之片段;非通用之 innerHTML 也。

## 限额

| 项 | 限 |
| --- | --- |
| 柄表 | 每客器四千零九十六项 |
| 一次建树 | 深至多三十二;节至多二千;文至多一 MiB(UTF-8);属性总量至多一 MiB;描述至多二 MiB |
| 替换页面子节点 | 至多二千项 |
| 查询页面节点 | 选择器至多五百一十二字;合者至多一千零二十四个元素 |
| 读取页面节点树 | 深至多三十二;节至多二千;文至多一 MiB |
| 设置页面节点超文本 | HTML 至多二 MiB;节至多五千;深至多三十二 |
| 文与追加 | 单次及单个文本节点至多八 MiB |
| 属性之值 | 至多六万五千五百三十六码元 |
| 页面资源 | 至多二 MiB,惟同源 GET |

## 跨宿主之一致

- 白册、限额、释放之规与败之类须合此文;宿主可更严,不可更宽。
- 柄号乃不透明之文,客惟原样传回;宿主不得使已释之柄号暗指他节(参考实现之号于实例内单调而增,永不复用)。
- 构建页面节点树之 id 唯一之验止于一次调用;建成插入文档而与既有 id 重,则从浏览器之法(取文档序之首),客当保 id 唯一。

## 一致性之例

1. 建树 `{"标签":"div","子":[{"标签":"script"}]}`:发事故,指其位“根.子[0]”,柄表不增。
2. 建二层之树,添加页面子节点于容器,再释放页面节点(根):节仍在文档,柄表复其旧数;循环一万次,柄表仍为旧数。
3. 容器有三行,各行及其子节皆尝取柄;清空页面子节点(容器)后,此诸柄尽无效,容器之柄仍有效。
4. 设置页面框架地址(“网站画面”,“https://evil.example/”):iframe 之 data-yy-frame-origins 无此 origin,发事故。
5. 装入页面模板所入之模板含 `<script>` 与 `onclick`:装入后文档无脚本元素,元素无 onclick。
6. (零点三点零)页有三个 `<a class="引用" href="/x">`:查询页面节点(“”,“.引用”)返三柄;读取页面节点属性(柄,“href”)为(阳,“/x”);读取页面节点父级(柄)乃其共父之柄;查找最近页面祖先(柄,“section”)得外层之 section。
7. (零点三点零)`<template id="资料"><a data-qualified="甲.乙" href="/a">甲</a></template>`:查询页面节点(取得页面节点(“资料”),“a[data-qualified]”)得模板内容中之 a(寻常之文档查询不见之)。
8. (零点三点零)`<code>ab<b class="k">cd</b></code>` 导为 `{"标签":"code","子":["ab",{"标签":"b","类":"k","子":["cd"]}]}`;原样授构建页面节点树,得等价之新树。
9. (零点三点零)替换页面节点(旧,新链)之后添加页面子节点(新链,旧):旧节仍有效,终位在新链之内,新链在原处。
10. (零点三点零)设置页面节点超文本(柄,`<span class="tok-k">甲</span>乙`)成;含 `<script>`、onclick 或 style 之 HTML 发事故,节点之内容不变。

## 界

此包不定:选择符查询之外之节点遍历(nextSibling、TreeWalker、Range 等:当以读取页面节点树于豫言中遍历之)、任意 CSS 与样式对象、img 与 svg、动态造 iframe、自定义元素、Shadow DOM、MutationObserver、文档片段。无文树之平台不供此包。