如何在保留 comments/style 的同时映射 CommentedMap?
How to map over a CommentedMap while preserving the comments/style?
给定一个 ruamel.yaml CommentedMap 和一些转换函数 f: CommentedMap → Any
,我想生成一个具有转换键和值的新 CommentedMap,但在其他方面尽可能与原始的相似。
如果我不关心保留样式,我可以这样做:
result = {
f(key) : f(value)
for key, value in my_commented_map.items()
}
如果我不需要转换密钥(而且我不关心改变原始密钥),我可以这样做:
for key, value in my_commented_map.items():
my_commented_map[key] = f(value)
样式和评论信息分别附在
CommentedMap
通过特殊属性。您可以复制的样式,但是
注释部分索引到它们出现在哪一行的键,并且
如果你转换那个键,你还需要转换那个索引
评论。
在您的第一个示例中,您将 f()
应用于键和值,我将使用
在我的例子中单独的函数,所有的键,和
全部小写值(这当然只适用于字符串类型
键和值,所以这是示例的限制,不是
解决方案)
import sys
import ruamel.yaml
from ruamel.yaml.comments import CommentedMap as CM
from ruamel.yaml.comments import Format, Comment
yaml_str = """\
# example YAML document
abc: All Strings are Equal # but some Strings are more Equal then others
klm: Flying Blue
xYz: the End # for now
"""
def fkey(s):
return s.upper()
def fval(s):
return s.lower()
def transform(data, fk, fv):
d = CM()
if hasattr(data, Format.attrib):
setattr(d, Format.attrib, getattr(data, Format.attrib))
ca = None
if hasattr(data, Comment.attrib):
setattr(d, Comment.attrib, getattr(data, Comment.attrib))
ca = getattr(d, Comment.attrib)
# as the key mapping could map new keys on old keys, first gather everything
key_com = {}
for k in data:
new_k = fk(k)
d[new_k] = fv(data[k])
if ca is not None and k in ca.items:
key_com[new_k] = ca.items.pop(k)
if ca is not None:
assert len(ca.items) == 0
ca._items = key_com # the attribute, not the read-only property
return d
yaml = ruamel.yaml.YAML()
data = yaml.load(yaml_str)
# the following will print any new CommentedMap with curly braces, this just here to check
# if the style attribute copying is working correctly, remove from real code
yaml.default_flow_style = True
data = transform(data, fkey, fval)
yaml.dump(data, sys.stdout)
给出:
# example YAML document
ABC: all strings are equal # but some Strings are more Equal then others
KLM: flying blue
XYZ: the end # for now
请注意:
以上尝试(并成功)在原文中开始评论
列,如果那是不可能的,例如当转换后的密钥或
值需要更多 space,它被进一步推向右边。
如果你有一个更复杂的数据结构,递归遍历树,下降到映射
和序列。在那种情况下,存储 (key, value, comment)
元组可能更容易
然后 pop()
所有键并重新插入存储的值(而不是重建树)。
给定一个 ruamel.yaml CommentedMap 和一些转换函数 f: CommentedMap → Any
,我想生成一个具有转换键和值的新 CommentedMap,但在其他方面尽可能与原始的相似。
如果我不关心保留样式,我可以这样做:
result = {
f(key) : f(value)
for key, value in my_commented_map.items()
}
如果我不需要转换密钥(而且我不关心改变原始密钥),我可以这样做:
for key, value in my_commented_map.items():
my_commented_map[key] = f(value)
样式和评论信息分别附在
CommentedMap
通过特殊属性。您可以复制的样式,但是
注释部分索引到它们出现在哪一行的键,并且
如果你转换那个键,你还需要转换那个索引
评论。
在您的第一个示例中,您将 f()
应用于键和值,我将使用
在我的例子中单独的函数,所有的键,和
全部小写值(这当然只适用于字符串类型
键和值,所以这是示例的限制,不是
解决方案)
import sys
import ruamel.yaml
from ruamel.yaml.comments import CommentedMap as CM
from ruamel.yaml.comments import Format, Comment
yaml_str = """\
# example YAML document
abc: All Strings are Equal # but some Strings are more Equal then others
klm: Flying Blue
xYz: the End # for now
"""
def fkey(s):
return s.upper()
def fval(s):
return s.lower()
def transform(data, fk, fv):
d = CM()
if hasattr(data, Format.attrib):
setattr(d, Format.attrib, getattr(data, Format.attrib))
ca = None
if hasattr(data, Comment.attrib):
setattr(d, Comment.attrib, getattr(data, Comment.attrib))
ca = getattr(d, Comment.attrib)
# as the key mapping could map new keys on old keys, first gather everything
key_com = {}
for k in data:
new_k = fk(k)
d[new_k] = fv(data[k])
if ca is not None and k in ca.items:
key_com[new_k] = ca.items.pop(k)
if ca is not None:
assert len(ca.items) == 0
ca._items = key_com # the attribute, not the read-only property
return d
yaml = ruamel.yaml.YAML()
data = yaml.load(yaml_str)
# the following will print any new CommentedMap with curly braces, this just here to check
# if the style attribute copying is working correctly, remove from real code
yaml.default_flow_style = True
data = transform(data, fkey, fval)
yaml.dump(data, sys.stdout)
给出:
# example YAML document
ABC: all strings are equal # but some Strings are more Equal then others
KLM: flying blue
XYZ: the end # for now
请注意:
以上尝试(并成功)在原文中开始评论 列,如果那是不可能的,例如当转换后的密钥或 值需要更多 space,它被进一步推向右边。
如果你有一个更复杂的数据结构,递归遍历树,下降到映射 和序列。在那种情况下,存储
(key, value, comment)
元组可能更容易 然后pop()
所有键并重新插入存储的值(而不是重建树)。