You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何利用jq、yq、xq将JSON/YAML转换为与原始XML结构一致的XML文件?

解决XML与JSON/YAML互转时的格式还原问题

这个问题我之前也碰到过,核心原因是你使用的yq 3.0.2版本比较老旧,它没有内置识别xq生成的特殊字段(@前缀代表XML属性、#text代表元素文本内容)的逻辑,所以直接转换会把这些字段当成普通子元素。下面给你两种可行的解决方案:

方案一:升级到mikefarah的yq v4+(推荐)

新版本的yq(v4.x及以上)和xq同属一个工具套件,原生支持xq的反向转换逻辑,能自动把@开头的字段解析为XML属性,#text解析为元素文本。

安装方式(Fedora 36)

你可以直接通过包管理器安装最新版:

sudo dnf install yq

如果dnf提供的版本不是v4,也可以下载官方编译好的二进制包替换旧版本。

测试转换

针对你的额外测试示例:

echo '<ele attr_name="attr_value">ele_value</ele>' | xq | yq -o=xml

会输出正确的XML结构:

<ele attr_name="attr_value">ele_value</ele>

针对你原始的JSON文件,直接执行:

yq -o=xml json_file

就能还原出带命名空间、属性的原始XML结构,比如security-settingsxmlns属性、security-settingmatch属性,以及permissiontyperoles属性都会正确保留。

方案二:用jq预处理JSON(适配旧版yq)

如果暂时无法升级yq,你可以通过jq编写过滤器,把xq生成的特殊字段转换成旧版yq能识别的XML结构。

编写jq过滤脚本

创建一个名为xmlify.jq的文件,内容如下(递归处理所有属性和文本):

def xmlify:
  if type == "object" then
    # 提取文本内容
    (if has("#text") then .["#text"] else null end) as $text
    # 处理所有字段:@开头的转为属性,其他转为子元素
    | (del(."#text") | to_entries | map(
        if .key | startswith("@") then
          {"attr": (.key[1:], .value)}
        else
          {"elem": (.key, (.value | xmlify))}
        end
      )) as $nodes
    # 拆分属性和子元素
    | ($nodes | map(select(has("attr"))) | map({key: .attr[0], value: .attr[1]}) | from_entries) as $attrs
    | ($nodes | map(select(has("elem"))) | map({(.elem[0]): .elem[1]})) as $elems
    # 组合成yq能识别的结构
    | if $text != null then
        $elems[0] + {$attrs} + {"#text": $text}
      else
        $elems[0] + {$attrs}
      end
  elif type == "array" then
    map(xmlify)
  else
    .
  end;
xmlify

执行转换

用jq预处理JSON后再用yq转XML:

cat json_file | jq -f xmlify.jq | yq -o=xml -P

这样就能生成和原始XML结构一致的输出。


内容的提问来源于stack exchange,提问作者Gullah Geechee

火山引擎 最新活动