yq split_doc 操作符实战将 YAML/JSON 结果拆分为独立文档的完整指南【免费下载链接】yqyq is a portable command-line YAML, JSON, XML, CSV, TOML, HCL and properties processor项目地址: https://gitcode.com/GitHub_Trending/yq/yq导读split_doc是 yq便携式命令行 YAML/JSON/XML/CSV/TOML/HCL/properties 处理器中用于将当前匹配到的所有节点重新分配为独立文档的核心操作符。本指南以仓库文档 split-into-documents.md 为骨架结合 operator_split_document.go 源码实现与 split-printer.sh 验收测试完整讲解split_doc的语义、语法别名、运行示例、底层实现原理以及与document_index、--split-exp等特性组合的实战方案。读完本文你将掌握如何在单条 yq 命令中把一个数组拆成多个文档、配合分隔符输出甚至批量拆分为独立文件。一、操作符语义什么是 split_doc按官方文档的定义split_docSplit into Documents操作符的作用是This operator splits all matches into separate documents 该操作符将所有匹配到的节点拆分为相互独立的文档。理解这一语义的关键点有两个它作用在匹配节点MatchingNodes上表达式左侧管道上游产生的每一个结果节点都会被重新提升为一个独立的顶级文档它改变的是文档边界而不是数据结构节点内容本身不被改写只是每个节点获得新的文档索引Document Index并在输出时以---文档分隔符彼此隔开。需要特别说明的是split_doc只作用于当前上下文中的匹配节点。如果直接对根节点调用split_doc由于匹配节点只有一个根节点本身输出的仍然是一个文档因此实战中通常先使用.[]或过滤器展开集合元素再交给split_doc拆分。二、语法与别名在词法层split_doc的识别规则定义在 lexer_participle.go{SplitDocument, splitDoc|split_?doc, opToken(splitDocumentOpType), 0},正则splitDoc|split_?doc说明该操作符支持以下等价写法splitDoc驼峰split_doc下划线split-doc连字符splitdoc其中split_doc是文档与社区中最常用的写法。在操作符注册表 operation.go 中它被定义为NumArgs: 0不接收参数、优先级 52 的零参数操作符因此直接以管道形式使用即可yq .[] | split_doc sample.yml三、基础运行示例继承官方文档3.1 拆分空输入官方文档给出的第一个示例是空输入场景。运行yq --null-input split_doc将输出即一个空文档。这一行为在单元测试 operator_split_document_test.go 的 Split empty 场景中得到印证对空文档执行split_doc结果为一个空节点(!!null)。3.2 拆分数组元素给定sample.yml文件内容为- a: cat - b: dog执行yq .[] | split_doc sample.yml将输出a: cat --- b: dog流程拆解.[]遍历数组产生两个匹配节点{a: cat}与{b: dog}split_doc将这两个节点分别提升为独立的顶级文档打印器在多个文档之间自动插入---分隔符。这与单元测试 Split array 场景的预期输出完全一致D0, P[0], (!!map)::{a: cat}与D1, P[1], (!!map)::{b: dog}。四、源码级原理split_doc 到底做了什么split_doc的核心实现非常精简完整代码位于 operator_split_document.gofunc splitDocumentOperator(_ *dataTreeNavigator, context Context, _ *ExpressionNode) (Context, error) { log.Debugf(splitDocumentOperator) var index uint for el : context.MatchingNodes.Front(); el ! nil; el el.Next() { candidate : el.Value.(*CandidateNode) candidate.SetDocument(index) candidate.SetParent(nil) index index 1 } return context, nil }逐行解读遍历匹配节点链context.MatchingNodes是当前上下文中的所有匹配节点双向链表操作符依次处理每一个分配文档索引candidate.SetDocument(index)为每个节点写入自增的文档号0, 1, 2, ...。这正是后续document_index操作符能读到的新索引值切断父节点candidate.SetParent(nil)将节点的父指针清空使节点脱离原有树形结构、成为新的文档根索引自增index index 1保证每个文档获得唯一编号。由此可见split_doc本质上是一个文档边界重组操作它不复制数据、不改变节点值只是重新分配哪个节点属于哪个文档。同时它注册了CheckForPostTraverse标记见 operation.go意味着操作符执行后仍允许后续表达式继续遍历见测试中的split_doc[]用法。五、与 document_index 配合验证拆分结果拆分后的文档索引可以通过document_index别名di读取。官方文档 document-index.md 说明了这一配套特性。对拆分结果逐一打印索引yq .[] | split_doc | document_index sample.yml输出0 --- 1也可使用di简写yq .[] | split_doc | di sample.yml更实用的场景是按索引过滤特定文档yq .[] | split_doc | select(document_index 1) sample.yml输出b: dog将匹配结果与其文档号打包输出yq .[] | split_doc | ({match: ., doc: document_index}) sample.yml输出match: a: cat doc: 0 --- match: b: dog doc: 1这套组合非常适合在多文档合并、分片处理等场景中精确追踪每个片段的来源。六、实战进阶用 --split-exp 把文档拆分为独立文件split_doc输出的是多个文档的流而 yq 的-s/--split-exp参数split printer可以直接将每个文档写入独立文件。仓库的验收测试 split-printer.sh 完整覆盖了这一能力。6.1 按字段值命名拆分文件yq e test.yml -s .a对内容为a: test_doc1与a: test_doc2的两文档输入会分别生成test_doc1.yml与test_doc2.yml。6.2 按索引命名yq e test.yml -s test_ $index将生成test_0.yml、test_1.yml。6.3 数组拆分到文件对数组输入- name: test_fred/- name: test_catherineyq e --no-doc -s .name .[] test.yml会生成test_fred.yml、test_catherine.yml两个文件且--no-doc使每个文件不额外打印文档分隔符。6.4 自定义扩展名与目录结构yq e test.yml -s .a .yaml yq e --no-doc -s .f test.yml # 支持 test_dir1/test_file1.yml 这类带目录的路径--split-exp的表达式返回值即输出文件路径因此可以自由拼接扩展名、目录乃至完整路径--split-exp-file则可将拆分表达式写入独立文件后引用yq test.yml --split-exp-file test_splitExp.yml七、测试与验证split_doc的正确性由两层测试保障单元测试operator_split_document_test.go通过splitDocOperatorScenarios覆盖三个场景——空文档拆分Split empty、数组拆分Split array、拆分后继续遍历Split splat表达式.[] | split_doc[]将每个叶子值再拆为独立文档测试末尾的documentOperatorScenarios(t, split-into-documents, ...)还会自动生成并核对本文所基于的官方文档快照验收测试split-printer.sh在真实 CLI 层面验证-s拆分、索引命名、自定义扩展名、目录拆分、--split-exp-file与eaeval-all模式等端到端行为。需要特别提醒运行验收测试中的./yq与-s命令会在本地创建输出文件属于正常使用方式测试自身也通过rm test*.yml || true在每次运行前清理产物。八、注意事项与使用建议区分e与ea模式yq e默认单文档评估与yq eaeval-all将多输入文档合并处理在拆分多输入文件时行为不同验收测试对两种模式均有覆盖用例多文件场景建议先用ea验证结果先展开再拆分对数组要先用.[]展开元素再调用split_doc否则只会拆分出一个根文档--no-doc控制分隔符当每个拆分结果本身就是完整文档时用--no-doc可避免文件内出现---头索引从 0 开始split_doc分配的文档索引从 0 递增与document_index/di读取到的值一一对应。九、总结split_doc是 yq 中实现一查多文档的关键操作符语义上它把所有匹配节点重新划分为独立文档实现上则是遍历匹配节点链、逐个写入自增文档索引并切断父指针见 operator_split_document.go配合document_index可精确追踪文档来源配合--split-exp可批量落盘为独立文件。掌握了它你就能在 CI 脚本、配置批量处理、多环境清单生成等场景中用一条表达式完成原本需要多步脚本才能实现的拆分工作。进一步阅读本文所依据的官方操作符文档 split-into-documents.md、配套索引文档 document-index.md、词法与操作符注册源码 lexer_participle.go 与 operation.go以及完整验收用例 split-printer.sh。【免费下载链接】yqyq is a portable command-line YAML, JSON, XML, CSV, TOML, HCL and properties processor项目地址: https://gitcode.com/GitHub_Trending/yq/yq创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
