在我所拥有的许多YAML文件中,通常存在以下内容:
query: "SELECT\n *\nFROM\n (SELECT\n 'apple' AS fruit,\n 'carrot' AS vegetable);"
但我想将上面的内容转换为如下所示:
query: >
SELECT
*
FROM (
SELECT
"apple" AS fruit,
"carrot" AS vegetable);
在YAML文件中。
我只是希望YAML更具可读性,我想要一种转换字符串的方法,而不必进入我拥有的每个YAML文件并手动更改它们。我已经尝试将上面的字符串打印到stdout并将该输出重定向到变量,但这对我不起作用。
我尝试过的代码:
from contextlib import redirect_stdout
import io
with io.StringIO() as buf, redirect_stdout(buf):
print(query)
yam['query'] = buf.getvalue()
但我只是用转义字符返回字符串。
使用折叠标量可能不是你想要的,因为根据spec:
折叠允许在单个空格字符分隔两个非空格字符的任何地方打破长行。
你有这样的线条,但不是全部。
此外,您的输出无效YAML,您需要将折叠线至少缩进一个空格。 (只有当它是文档中的唯一节点时,您不必缩进折叠或文字标量的唯一时间。)
最后因为你只使用>
,你会在加载值的末尾有一个换行符,即在分号之后,原始语中没有。
我建议你选择文字标量,其中每个换行符都是换行符。如果您的文件位于input.yaml
中,则以下将处理与您设置的条件匹配的任何值行:
import sys
from pathlib import Path
import ruamel.yaml
def try_convert(s):
"""return None if not converted"""
if 'SELECT' not in s:
return None
if '\n' not in s:
return None
return ruamel.yaml.scalarstring.LiteralScalarString(s)
def recurse(d):
"""this walks recursively over the datastructure you loaded, entering elements of list,
and values of mappings
"""
if isinstance(d, dict):
for k in d:
v = d[k]
res = try_convert(v)
if res is not None:
d[k] = res
else:
recurse(d[k])
elif isinstance(d, list):
for idx, elem in enumerate(d):
res = try_convert(elem)
if res is not None:
d[idx] = res
else:
recurse(d)
# nothing to do for scalars, which means a scalar in the root of a document will not be converted
file_name = Path('input.yaml')
yaml = ruamel.yaml.YAML()
data = yaml.load(file_name)
recurse(data)
yaml.dump(data, sys.stdout)
这使:
query: |-
SELECT
*
FROM
(SELECT
'apple' AS fruit,
'carrot' AS vegetable);
在文字样式指示符(-
)之后的条带选择指示符(|
)在该标量的末尾删除任意数量的换行符,因此在加载时,在分号后将没有额外的换行符。
你当然可以在转换中调用一些SQL prettyprinter。只要它的输出是有效的SQL并包含换行符,你可以将它传递给LiteralScalarString
并从try_convert()
返回它