【问题标题】:Converting HTML to Draft-JS ContentState in Python/Django在 Python/Django 中将 HTML 转换为 Draft-JS ContentState
【发布时间】:2020-04-15 18:03:13
【问题描述】:

我正在从使用 html 所见即所得编辑器 (CKEditor) 迁移到使用 Draft-JS,并且希望能够在 Django 迁移中将现有 HTML 数据转换为 Draft-JS ContentState,但我一直无法找到方法这样做。

这可能吗?或者这甚至是正确的方法?

【问题讨论】:

    标签: python django reactjs draftjs


    【解决方案1】:

    我面临同样的情况,我的目标是使用 BeautifulSoup 递归解析 HTML 文档,并使用一些辅助函数将块构建为 Python 对象(您可以使用 DraftJS 的 Python 库替换此步骤) .这样,您将对转换有 100% 的控制权,并且可以完全控制 DraftJS 文档,并对自定义块渲染和元素映射进行深思熟虑。

    只要你挽起袖子,这真的不难。当没有可用的库时,我曾经担心会出现此类问题,但现在绝对不介意有机会不为此类简单任务包含另一个依赖项。

    编辑

    进一步考虑,您应该考虑在 NodeJS 中使用 DraftJS HTML->DraftJS 库来执行此过程。

    我没有时间用它制作一个库,但这里有一个使用BeautifulSoup 执行此操作的代码的初始版本,应该可以帮助您入门:

    import uuid
    
    from bs4 import BeautifulSoup
    from bs4.element import NavigableString
    
    
    INLINE_TAGNAMES = ['b', 'strong', 'i', 'em', 'u']
    INLINE_ENTITIES = ['a']
    """
    Expects a body object (which is probably stored and used as JSON)
    """
    def add_html_to_body(html, body=None):
        if body:
            body = body.copy()
        else:
            body = {'entityMap':{}, 'blocks': []}
    
        soup = BeautifulSoup(html, 'lxml')
        _element_to_block([soup.body], body['blocks'], body['entityMap'])
    
        return body
    
    
    def _element_to_block(parent_els, blocks, entity_map):
        has_blocks = len(blocks)
        if not has_blocks:
            blocks.append(_create_block('', 'unstyled', [], []))
    
        last_block = blocks[-1]
        parent_el = parent_els[-1]
    
        for el in parent_el.contents:
            if type(el) == NavigableString:
                # If this is part of an inline range, set it's length.
                reversed_parent_els = parent_els[:]
                reversed_parent_els.reverse()
    
                # Keep a track of the number of parent style and entity tags
                # we have already passed.
                inline_tagnames_counter = 0
                inline_entities_counter = 0
    
                for i in xrange(len(reversed_parent_els)):
                    ancestor = reversed_parent_els[i]
    
                    if ancestor.name in INLINE_TAGNAMES:
                        inline_tagnames_counter += 1
                        last_block['inlineStyleRanges'][-1 * inline_tagnames_counter]['length'] += len(el.string)
                    elif ancestor.name in INLINE_ENTITIES:
                        inline_entities_counter += 1
                        last_block['entityRanges'][-1 * inline_entities_counter]['length'] += len(el.string)
    
                last_block['text'] += el.string
    
            elif el.name in ['b', 'strong']:
                last_block['inlineStyleRanges'].append({
                    'offset': len(last_block['text']),
                    'length': 0,
                    'style': 'BOLD'
                })
                _element_to_block(parent_els[:] + [el], blocks, entity_map)
    
            elif el.name in ['i', 'em']:
                last_block['inlineStyleRanges'].append({
                    'offset': len(last_block['text']),
                    'length': 0,
                    'style': 'ITALIC'
                })
                _element_to_block(parent_els[:] + [el], blocks, entity_map)
    
            elif el.name in ['div', 'p']:
                # If the parent didn't give blocks, we create an empty starting one.
                if has_blocks:
                    blocks.append(_create_block(el.string or '', 'unstyled', [], []))
    
                _element_to_block([el], blocks, entity_map)
    
            elif el.name == 'a':
                # Create entity here.
                entity_key = str(uuid.uuid4())[:8]
                last_block['entityRanges'].append({
                    'offset': len(last_block['text']),
                    'length': len(el.string or ''),
                    'key': entity_key
                })
                entity_map[entity_key] = {
                    'type': 'LINK',
                    'mutability': 'IMMUTABLE',
                    'data': { 'url': el.get('href') }
                }
                _element_to_block(parent_els[:] + [el], blocks, entity_map)
    
            # More elses based on the kind of elements you expect to see like
            # u, ul, li, li, h1, h2, h3, table, etc. and entities with 'atomic' stuff.
    
    
    def _create_block(text, type, inline_style_ranges, entity_ranges, data={}):
        return {
            'text': text,
            'type': type,
            'inlineStyleRanges': inline_style_ranges,
            'entityRanges': entity_ranges,
            'depth': 0,
            'data': data,
            'key': str(uuid.uuid4())[:8]
        }
    

    【讨论】:

    • 是的 - 我最终自动化了将 html 导出到 NodeJS 然后处理并将其保存为 json 并将其导入回来的任务。+
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-12-22
    • 2021-04-02
    • 1970-01-01
    • 1970-01-01
    • 2016-06-20
    • 2017-05-06
    • 1970-01-01
    相关资源
    最近更新 更多