将类似 DOM 的结构转换为降价的有效方法
Efficient way to convert DOM-like structure to markdown
所以我有一个类似 DOM 的树,我正在尝试将其转换为 markdown。例如它可以看起来像这样
[
{
'type': 'header',
'attr': {
'size': 2
},
'children': [
'A header, ',
{
'type': 'link',
'attr': {
'url': 'https://www.google.com'
},
'children': 'a link inside a header'
}
]
},
'some more text'
]
我想要的输出是
## A header, [a link inside a header](https://www.google.com)
some more text
我试过了
def genMd(tree):
md_string = ''
for element in tree:
if type(element) == str:
md_string += element
elif type(element) == dict:
if element['type'] == 'header':
md_string += '{} {}\n'.format('#' * element['attr']['size'], genMd(element['children']))
elif element['type'] == 'link':
md_string += '[{}]({})'.format(genMd(element['children']), element['attr']['url']
# I would add more if statements here for the other cases
return md_string
这行得通,但似乎效率很低,我最终会得到大量的 if 语句。我也试过这个
def genMd(tree):
MD_TABLE = {
'header': '\'{} {}\n\'.format(\'#\' * element[\'attr\'][\'size\'], genMd(element[\'children\']))',
'link': '\'[{}]({})\'.format(genMd(element[\'children\']), element[\'attr\'][\'url\'])'
# More entries here for the other cases
}
md_string = ''
for element in tree:
if type(element) == str:
md_string += element
elif type(element) == dict:
md_string += eval(MD_TABLE[element['type']])
return md_string
也能用,但感觉还是不对。
TL;DR:使用 if 语句感觉不对,有更好的方法吗?
另一种方法可能包括使用生成器函数遍历 DOM 树,同时保留单独的函数来处理各种类型的特定格式:
def markdown(d):
def m_header(a):
yield f"{'#'*a['attr']['size']} "+' '.join(markdown(a['children']))
def m_link(a):
yield f'[{" ".join(markdown(a["children"]))}]({a["attr"]["url"]})'
types = {'header':m_header, 'link':m_link}
for i in ([d] if not isinstance(d, list) else d):
if not isinstance(i, dict):
yield i
else:
yield from types[i['type']](i)
dom = [{'type': 'header', 'attr': {'size': 2}, 'children': ['A header, ', {'type': 'link', 'attr': {'url': 'https://www.google.com'}, 'children': 'a link inside a header'}]}, 'some more text']
print('\n'.join(markdown(dom)))
输出:
## A header, [a link inside a header](https://www.google.com)
some more text
一些观察:
- 通过使用带有
str.join
的生成器,您不需要通过 +=
连续连接字符串,从而使代码更清晰并且 increased efficiency.
- 使用函数为特定类型生成标记比使用带有
eval
的字符串格式更易于维护和更安全。
所以我有一个类似 DOM 的树,我正在尝试将其转换为 markdown。例如它可以看起来像这样
[
{
'type': 'header',
'attr': {
'size': 2
},
'children': [
'A header, ',
{
'type': 'link',
'attr': {
'url': 'https://www.google.com'
},
'children': 'a link inside a header'
}
]
},
'some more text'
]
我想要的输出是
## A header, [a link inside a header](https://www.google.com)
some more text
我试过了
def genMd(tree):
md_string = ''
for element in tree:
if type(element) == str:
md_string += element
elif type(element) == dict:
if element['type'] == 'header':
md_string += '{} {}\n'.format('#' * element['attr']['size'], genMd(element['children']))
elif element['type'] == 'link':
md_string += '[{}]({})'.format(genMd(element['children']), element['attr']['url']
# I would add more if statements here for the other cases
return md_string
这行得通,但似乎效率很低,我最终会得到大量的 if 语句。我也试过这个
def genMd(tree):
MD_TABLE = {
'header': '\'{} {}\n\'.format(\'#\' * element[\'attr\'][\'size\'], genMd(element[\'children\']))',
'link': '\'[{}]({})\'.format(genMd(element[\'children\']), element[\'attr\'][\'url\'])'
# More entries here for the other cases
}
md_string = ''
for element in tree:
if type(element) == str:
md_string += element
elif type(element) == dict:
md_string += eval(MD_TABLE[element['type']])
return md_string
也能用,但感觉还是不对。
TL;DR:使用 if 语句感觉不对,有更好的方法吗?
另一种方法可能包括使用生成器函数遍历 DOM 树,同时保留单独的函数来处理各种类型的特定格式:
def markdown(d):
def m_header(a):
yield f"{'#'*a['attr']['size']} "+' '.join(markdown(a['children']))
def m_link(a):
yield f'[{" ".join(markdown(a["children"]))}]({a["attr"]["url"]})'
types = {'header':m_header, 'link':m_link}
for i in ([d] if not isinstance(d, list) else d):
if not isinstance(i, dict):
yield i
else:
yield from types[i['type']](i)
dom = [{'type': 'header', 'attr': {'size': 2}, 'children': ['A header, ', {'type': 'link', 'attr': {'url': 'https://www.google.com'}, 'children': 'a link inside a header'}]}, 'some more text']
print('\n'.join(markdown(dom)))
输出:
## A header, [a link inside a header](https://www.google.com)
some more text
一些观察:
- 通过使用带有
str.join
的生成器,您不需要通过+=
连续连接字符串,从而使代码更清晰并且 increased efficiency. - 使用函数为特定类型生成标记比使用带有
eval
的字符串格式更易于维护和更安全。