ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

yq 实战指南:Properties 属性的编码、解码与 Roundtrip 全解析

yq 实战指南:Properties 属性的编码、解码与 Roundtrip 全解析 yq 实战指南Properties 属性的编码、解码与 Roundtrip 全解析【免费下载链接】yqyq is a portable command-line YAML, JSON, XML, CSV, TOML, HCL and properties processor项目地址: https://gitcode.com/GitHub_Trending/yq/yq本文基于 yq 官方文档 properties.md 展开系统讲解 yq 如何在 YAML 与 Java properties 文件之间做编码-oprops、解码-pprops与原地转换roundtrip覆盖数组括号语法SpringBoot 风格、自定义键值分隔符、标量引号包裹、注释保留等全部配置选项并结合 源码实现 说明每个选项在底层是如何生效的。读完本文你可以将 yq 用于 SpringBoot 配置生成、properties 文件的批处理修改与多格式互换等实际场景。1. 格式注册props 是什么在 yq 中properties 是一种内置的数据格式。从源码 format.go 可以看到其注册定义var PropertiesFormat Format{props, []string{p, properties}, func() Encoder { return NewPropertiesEncoder(ConfiguredPropertiesPreferences) }, func() Decoder { return NewPropertiesDecoder() },这说明props是格式的主名称p和properties是它的别名因此下面这些写法等价yq -oprops sample.yml # 输出为 properties yq -oproperties sample.yml # 同上 yq -pprops sample.properties # 输入为 properties yq -pproperties sample.properties格式相关的两个核心偏好项定义在 properties.gotype PropertiesPreferences struct { UnwrapScalar bool KeyValueSeparator string UseArrayBrackets bool } func NewDefaultPropertiesPreferences() PropertiesPreferences { return PropertiesPreferences{ UnwrapScalar: true, KeyValueSeparator: , UseArrayBrackets: false, } }这三个字段正好对应命令行上可用的三个开关偏好项命令行参数默认值作用UnwrapScalar--unwrapScalar/-rtrue是否去掉标量的引号包裹设为false时含空格的字符串值会加双引号KeyValueSeparator--properties-separator 键与值之间的分隔符UseArrayBrackets--properties-array-bracketsfalse数组索引使用[x]还是.x形式前两个开关在 cmd/root.go 中注册rootCmd.PersistentFlags().StringVar(yqlib.ConfiguredPropertiesPreferences.KeyValueSeparator, properties-separator, ..., separator to use between keys and values) rootCmd.PersistentFlags().BoolVar(yqlib.ConfiguredPropertiesPreferences.UseArrayBrackets, properties-array-brackets, ..., use [x] in array paths (e.g. for SpringBoot))而--unwrapScalar是一个全局参数见 cmd/root.go对 properties 输出同样生效当输出格式为 properties 时unwrapScalar默认被置为true见 cmd/utils.go用户显式传参后则以用户设置为准。2. 编码YAML 转 properties2.1 基础用法与注释规则默认情况下空的 map 和数组不会被编码输出。给定sample.yml# block comments come through person: # neither do comments on maps name: Mike Wazowski # comments on values appear pets: - cat # comments on array values appear - nested: - list entry food: [pizza] # comments on arrays do not emptyArray: [] emptyMap: []执行yq -oprops sample.yml输出为# block comments come through # comments on values appear person.name Mike Wazowski # comments on array values appear person.pets.0 cat person.pets.1.nested.0 list entry person.food.0 pizza从输出可以总结出几条关键规则嵌套键被扁平化为点号分隔路径person.name、person.pets.1.nested.0数组索引以.0、.1形式内联在路径中块注释文档开头的#行会被保留值节点上的行尾注释如Mike Wazowski后面的注释也会被复制到对应键之前但 map 节点上的注释person:行上的# neither do comments on maps以及 flow 风格数组[pizza]上的注释不会被保留emptyArray/emptyMap这两个空节点没有出现在输出中。这些行为在编码器实现 encoder_properties.go 中可以看到对应逻辑编码是递归的doEncode过程每到一个节点都会把 key 节点与该节点自身的头注释、行注释拼起来调用p.SetComments(path, ...)挂到 properties 库的键上appendPath方法encoder_properties.go负责把数组下标拼进路径。仓库中的 examples/example.properties 就是一个符合上述输出形态的真实示例文件# comments on values appear person.name Mike # comments on array values appear person.pets.0 cat person.food.0 pizza2.2 数组括号语法--properties-array-brackets如果你的下游消费者是 SpringBoot 之类的框架它要求数组路径写成方括号形式例如person.pets[0]。声明--properties-array-brackets标志即可切换yq -oprops --properties-array-brackets sample.yml输出变为# block comments come through # comments on values appear person.name Mike Wazowski # comments on array values appear person.pets[0] cat person.pets[1].nested[0] list entry person.food[0] pizza对照 encoder_properties.go 中的appendPath可以确认这个开关的作用点——当 key 是int类型且UseArrayBrackets为真时走path[key]分支否则一律用path.keyswitch key.(type) { case int: if pe.prefs.UseArrayBrackets { return fmt.Sprintf(%v[%v], path, key) } } return fmt.Sprintf(%v.%v, path, key)这个开关是双向的解码端同样会识别方括号。decoder_properties.go 的parsePropKey先按键上的.切分若开启括号模式且段内含[则交给parsePropKeyArrayBracketSegment解析出「前缀 多个连续下标」支持user.credentials[0]、甚至嵌套的user.clowns[0][1]。相关用例在 properties_test.go 中有验证例如user.credentials[0].usernameuser1 user.credentials[0].password$2b$08$...可被正确解码为user: credentials: - username: user1 password: $2b$08$...2.3 自定义键值分隔符--properties-separator默认分隔符是前后各一个空格。用--properties-separator可以换成任意字符串yq -oprops --properties-separator : sample.yml输出# block comments come through # comments on values appear person.name : Mike Wazowski # comments on array values appear person.pets.0 : cat person.pets.1.nested.0 : list entry person.food.0 : pizza源码中该值直接传给 properties 库的WriteSeparator见 encoder_properties.go 的p.WriteSeparator pe.prefs.KeyValueSeparator因此编码与最终写出完全由这一个字段决定。2.4 标量引号包裹--unwrapScalarfalse默认unwrapScalar为true即输出时「解包」标量、不加引号。但如果把该参数设为false包含空格字符的字符串值会被双引号包裹yq -oprops --unwrapScalarfalse sample.yml输出# block comments come through # comments on values appear person.name Mike Wazowski # comments on array values appear person.pets.0 cat person.pets.1.nested.0 list entry person.food.0 pizza判断逻辑在 encoder_properties.go只有当UnwrapScalar为假且值中含空格时才调用fmt.Sprintf(%q, node.Value)加引号像cat、pizza这类无空格值始终裸输出。这个开关适合生成需要严格区分「值本身是否含空格」的配置文件。2.5 去掉注释... comments properties 的注释保留来自 YAML 侧的注释节点。如果希望输出完全干净用 yq 表达式先把所有注释清空即可yq -oprops ... comments sample.yml输出person.name Mike Wazowski person.pets.0 cat person.pets.1.nested.0 list entry person.food.0 pizza这里...遍历文档中每个节点comments 是注释操作符的赋值用法把头注释与行注释都置空编码器自然就没有可写的注释了。2.6 编码空 map 与空数组回到开头的默认行为空 map 和空数组不会出现在输出中properties 文件本身没有「空键」的语义这是格式层面的限制。如果需要把它们保留下来可以借助 yq 表达式把空节点改写为你想要的标量值yq -oprops (.. | select( (tag !!map or tag !!seq) and length 0)) sample.yml输出中追加了# block comments come through # comments on values appear person.name Mike Wazowski # comments on array values appear person.pets.0 cat person.pets.1.nested.0 list entry person.food.0 pizza emptyArray emptyMap 表达式拆解..递归遍历所有节点select((tag !!map or tag !!seq) and length 0)挑出空的映射与序列再整体 赋成空字符串标量编码器就会为它们写出key 的行。若你想保留「这里曾是个数组」的信息也可以改成 [empty]之类的自定义值。3. 解码properties 转 YAML给定sample.properties# block comments come through # comments on values appear person.name Mike Wazowski # comments on array values appear person.pets.0 cat person.pets.1.nested.0 list entry person.food.0 pizza执行yq -pprops sample.properties输出person: # block comments come through # comments on values appear name: Mike Wazowski pets: # comments on array values appear - cat - nested: - list entry food: - pizza解码过程在 decoder_properties.go 中先用 properties 库LoadString载入全部键值然后遍历properties.Keys()对每个键调用parsePropKey把点号路径解析为路径片段数组纯数字段会被strconv.ParseInt转成int从而在重建时成为数组索引再对根 map 执行DeeplyAssign逐层赋值。注释则通过applyPropertyCommentsdecoder_properties.go以 assign 表达式回写到对应键节点的HeadComment上——这就是为什么 YAML 输出里的注释位置与 properties 文件中一致。两个值得注意的实现细节值不会自动展开。Decode中显式设置了properties.DisableExpansion truedecoder_properties.go因此mike ${dontExpand} this会原样保留${dontExpand}字面量不会触发 properties 库的变量展开。该行为有专门测试覆盖properties_test.go。所有值默认都是字符串。这与 Java properties 的语义一致带来下面两个常用技巧。3.1 数字用from_yaml自动转类型properties 解析出来的值一律是!!str标签。若a.b 10默认会得到字符串10。要还原成真正的数字可以用from_yaml对所有字符串值做一次自动类型解析yq -pprops (.. | select(tag !!str)) | from_yaml sample.properties对输入a.b 10输出a: b: 10from_yaml会按 YAML 规则推断标量类型数字、布尔等配合.. | select(tag !!str)就实现了「全量类型还原」。3.2 数字键用array_to_map把数组还原为 map解码时数字路径段会被当作数组索引。如果原始 properties 文件里的数字其实是map 的键例如things.10 mike解码会得到数组而不是映射此时用array_to_map修正yq -pprops .things | array_to_map sample.properties对输入things.10 mike输出things: 10: mike这正是「解码时 int 段 → 数组下标」规则decoder_properties.go 中strconv.ParseInt成功即append(path, num)的镜像操作既然编码端能把 map 拍平解码端也能把「形似数组的连续数字键」重新收拢成 map。4. Roundtripproperties 原地修改最实用的场景是「读 properties → 改一个值 → 写回 properties」。由于解码保留了解析出的键、路径与注释信息yq 可以做到结构级改写yq -pprops -oprops .person.pets.0 dog sample.properties输入见上文第 3 节输出# block comments come through # comments on values appear person.name Mike Wazowski # comments on array values appear person.pets.0 dog person.pets.1.nested.0 list entry person.food.0 pizza可以看到只有person.pets.0的值从cat变成了dog其余键的顺序、空行和注释全部原样保留。配合-i--inplace标志还可以直接改写文件本体。这个 roundtrip 行为由 properties_test.go 的 Roundtrip 场景以及「comments on arrays roundtrip」「comments on map roundtrip」等场景持续验证测试文件同时驱动 usage/properties.md 文档的生成见 properties_test.go 的documentScenarios调用因此文档中的每个示例输出都与当前代码实际行为一致。5. 参数速查与适用边界把全文选项汇总参数默认说明-oprops/-oproperties—输出为 properties 格式-pprops/-pproperties—输入为 properties 格式--properties-array-bracketsfalse数组路径用[x]形式SpringBoot 风格解码时同样生效--properties-separator... 键值分隔符任意字符串--unwrapScalarfalse-rfalsetrue含空格的字符串值加双引号输出... comments —表达式技巧输出前清空所有注释几点适用前提与限制使用时请留意空 map/数组默认不输出需要显式赋标量值才能写出对应行map 节点与 flow 数组上的注释不保留只有值节点与数组元素值上的注释会随行输出解码值全部为字符串数字/布尔需配合from_yaml数字键会被当数组索引需要array_to_map纠正值中的${...}不会被展开DisableExpansion已开启对含密码哈希如$2b$08$...的配置尤其友好properties 格式不支持 YAML 锚点/别名编码器CanHandleAliases()返回false见 encoder_properties.go源文档含别名时请先展开再转换。6. 小结yq 把 properties 当作与 YAML 对等的一等格式编码端负责「扁平化 注释搬运 三种可配置风格点号/括号、分隔符、引号」解码端负责「点号路径重建 注释回写 字符串语义保留」两端组合即得可保留注释与结构的 roundtrip 能力。相关实现集中在 properties.go、encoder_properties.go 与 decoder_properties.go参数注册在 cmd/root.go行为测试与文档生成在 properties_test.go。在维护 SpringBoot 配置、Java properties 文件或需要在多种格式间做无损转换的场景中这些能力可以直接落地使用。【免费下载链接】yqyq is a portable command-line YAML, JSON, XML, CSV, TOML, HCL and properties processor项目地址: https://gitcode.com/GitHub_Trending/yq/yq创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表