docx2html/core.py
def build_list(li_nodes, meta_data):
    """
    Build the list structure and return the root list
    """
    # Need to keep track of all incomplete nested lists.
    ol_dict = {}

    # Need to keep track of the current indentation level.
    current_ilvl = -1

    # Need to keep track of the current list id.
    current_numId = -1

    # Need to keep track of list that new li tags should be added too.
    current_ol = None

    # Store the first list created (the root list) for the return value.
    root_ol = None
    visited_nodes = []
    list_contents = []

    def _build_li(list_contents):
        data = '<br />'.join(t for t in list_contents if t is not None)
        return etree.XML('<li>%s</li>' % data)

    def _build_non_li_content(el, meta_data):
        w_namespace = get_namespace(el, 'w')
        if el.tag == '%stbl' % w_namespace:
            new_el, visited_nodes = build_table(el, meta_data)
            return etree.tostring(new_el), visited_nodes
        elif el.tag == '%sp' % w_namespace:
            return get_element_content(el, meta_data), [el]
        if has_text(el):
            raise UnintendedTag('Did not expect %s' % el.tag)

    def _merge_lists(ilvl, current_ilvl, ol_dict, current_ol):
        for i in reversed(range(ilvl, current_ilvl)):
            # Any list that is more indented that ilvl needs to
            # be merged to the list before it.
            if i not in ol_dict:
                continue
            if ol_dict[i] is not current_ol:
                if ol_dict[i] is current_ol:
                    continue
                ol_dict[i][-1].append(current_ol)
                current_ol = ol_dict[i]

        # Clean up finished nested lists.
        for key in list(ol_dict):
            if key > ilvl:
                del ol_dict[key]
        return current_ol

    for li_node in li_nodes:
        w_namespace = get_namespace(li_node, 'w')
        if not is_li(li_node, meta_data):
            # Get the content and visited nodes
            new_el, el_visited_nodes = _build_non_li_content(
                li_node,
                meta_data,
            )
            list_contents.append(new_el)
            visited_nodes.extend(el_visited_nodes)
            continue
        if list_contents:
            li_el = _build_li(list_contents)
            list_contents = []
            current_ol.append(li_el)
        # Get the data needed to build the current list item
        list_contents.append(get_element_content(
            li_node,
            meta_data,
        ))
        ilvl = get_ilvl(li_node, w_namespace)
        numId = get_numId(li_node, w_namespace)
        list_type = get_ordered_list_type(meta_data, numId, ilvl)

        # If the ilvl is greater than the current_ilvl or the list id is
        # changing then we have the first li tag in a nested list. We need to
        # create a new list object and update all of our variables for keeping
        # track.
        if (ilvl > current_ilvl) or (numId != current_numId):
            # Only create a new list
            ol_dict[ilvl] = create_list(list_type)
            current_ol = ol_dict[ilvl]
            current_ilvl = ilvl
            current_numId = numId
        # Both cases above are not True then we need to close all lists greater
        # than ilvl and then remove them from the ol_dict
        else:
            # Merge any nested lists that need to be merged.
            current_ol = _merge_lists(
                ilvl=ilvl,
                current_ilvl=current_ilvl,
                ol_dict=ol_dict,
                current_ol=current_ol,
            )

        # Set the root list after the first list is created.
        if root_ol is None:
            root_ol = current_ol

        # Set the current list.
        if ilvl in ol_dict:
            current_ol = ol_dict[ilvl]
        else:
            # In some instances the ilvl is not in the ol_dict, if that is the
            # case, create it here (not sure how this happens but it has
            # before.) Only do this if the current_ol is not the root_ol,
            # otherwise etree will crash.

            if current_ol is not root_ol:

                # Merge the current_ol into the root_ol. _merge_lists is not
                # equipped to handle this situation since the only way to get
                # into this block of code is to have mangled ilvls.
                root_ol[-1].append(current_ol)

                # Reset the current_ol
                current_ol = create_list(list_type)

        # Create the li element.
        visited_nodes.extend(list(li_node.iter()))

    # If a list item is the last thing in a document, then you will need to add
    # it here. Should probably figure out how to get the above logic to deal
    # with it.
    if list_contents:
        li_el = _build_li(list_contents)
        list_contents = []
        current_ol.append(li_el)

    # Merge up any nested lists that have not been merged.
    current_ol = _merge_lists(
        ilvl=0,
        current_ilvl=current_ilvl,
        ol_dict=ol_dict,
        current_ol=current_ol,
    )

    return root_ol, visited_nodes
def build_list(li_nodes, meta_data):
    # Need to keep track of all incomplete nested lists.
    ol_dict = {}

    # Need to keep track of the current indentation level.
    current_ilvl = -1

    # Need to keep track of the current list id.
    current_numId = -1

    # Need to keep track of list that new li tags should be added too.
    current_ol = None

    # Store the first list created (the root list) for the return value.
    root_ol = None
    visited_nodes = []
    list_contents = []

    def _build_li(list_contents):
        data = '<br />'.join(t for t in list_contents if t is not None)
        return etree.XML('<li>%s</li>' % data)

    def _build_non_li_content(el, meta_data):
        w_namespace = get_namespace(el, 'w')
        if el.tag == '%stbl' % w_namespace:
            new_el, visited_nodes = build_table(el, meta_data)
            return etree.tostring(new_el), visited_nodes
        elif el.tag == '%sp' % w_namespace:
            return get_element_content(el, meta_data), [el]
        if has_text(el):
            raise UnintendedTag('Did not expect %s' % el.tag)

    def _merge_lists(ilvl, current_ilvl, ol_dict, current_ol):
        for i in reversed(range(ilvl, current_ilvl)):
            # Any list that is more indented that ilvl needs to
            # be merged to the list before it.
            if i not in ol_dict:
                continue
            if ol_dict[i] is not current_ol:
                if ol_dict[i] is current_ol:
                    continue
                ol_dict[i][-1].append(current_ol)
                current_ol = ol_dict[i]

        # Clean up finished nested lists.
        for key in list(ol_dict):
            if key > ilvl:
                del ol_dict[key]
        return current_ol

    for li_node in li_nodes:
        w_namespace = get_namespace(li_node, 'w')
        if not is_li(li_node, meta_data):
            # Get the content and visited nodes
            new_el, el_visited_nodes = _build_non_li_content(
                li_node,
                meta_data,
            )
            list_contents.append(new_el)
            visited_nodes.extend(el_visited_nodes)
            continue
        if list_contents:
            li_el = _build_li(list_contents)
            list_contents = []
            current_ol.append(li_el)
        # Get the data needed to build the current list item
        list_contents.append(get_element_content(
            li_node,
            meta_data,
        ))
        ilvl = get_ilvl(li_node, w_namespace)
        numId = get_numId(li_node, w_namespace)
        list_type = get_ordered_list_type(meta_data, numId, ilvl)

        # If the ilvl is greater than the current_ilvl or the list id is
        # changing then we have the first li tag in a nested list. We need to
        # create a new list object and update all of our variables for keeping
        # track.
        if (ilvl > current_ilvl) or (numId != current_numId):
            # Only create a new list
            ol_dict[ilvl] = create_list(list_type)
            current_ol = ol_dict[ilvl]
            current_ilvl = ilvl
            current_numId = numId
        # Both cases above are not True then we need to close all lists greater
        # than ilvl and then remove them from the ol_dict
        else:
            # Merge any nested lists that need to be merged.
            current_ol = _merge_lists(
                ilvl=ilvl,
                current_ilvl=current_ilvl,
                ol_dict=ol_dict,
                current_ol=current_ol,
            )

        # Set the root list after the first list is created.
        if root_ol is None:
            root_ol = current_ol

        # Set the current list.
        if ilvl in ol_dict:
            current_ol = ol_dict[ilvl]
        else:
            # In some instances the ilvl is not in the ol_dict, if that is the
            # case, create it here (not sure how this happens but it has
            # before.) Only do this if the current_ol is not the root_ol,
            # otherwise etree will crash.

            if current_ol is not root_ol:

                # Merge the current_ol into the root_ol. _merge_lists is not
                # equipped to handle this situation since the only way to get
                # into this block of code is to have mangled ilvls.
                root_ol[-1].append(current_ol)

                # Reset the current_ol
                current_ol = create_list(list_type)

        # Create the li element.
        visited_nodes.extend(list(li_node.iter()))

    # If a list item is the last thing in a document, then you will need to add
    # it here. Should probably figure out how to get the above logic to deal
    # with it.
    if list_contents:
        li_el = _build_li(list_contents)
        list_contents = []
        current_ol.append(li_el)

    # Merge up any nested lists that have not been merged.
    current_ol = _merge_lists(
        ilvl=0,
        current_ilvl=current_ilvl,
        ol_dict=ol_dict,
        current_ol=current_ol,
    )

    return root_ol, visited_nodes
def build_list ( li_nodes , meta_data ) : # Need to keep track of all incomplete nested lists. ol_dict = { } # Need to keep track of the current indentation level. current_ilvl = - 1 # Need to keep track of the current list id. current_numId = - 1 # Need to keep track of list that new li tags should be added too. current_ol = None # Store the first list created (the root list) for the return value. root_ol = None visited_nodes = [ ] list_contents = [ ] def _build_li ( list_contents ) : data = '<br />' . join ( t for t in list_contents if t is not None ) return etree . XML ( '<li>%s</li>' % data ) def _build_non_li_content ( el , meta_data ) : w_namespace = get_namespace ( el , 'w' ) if el . tag == '%stbl' % w_namespace : new_el , visited_nodes = build_table ( el , meta_data ) return etree . tostring ( new_el ) , visited_nodes elif el . tag == '%sp' % w_namespace : return get_element_content ( el , meta_data ) , [ el ] if has_text ( el ) : raise UnintendedTag ( 'Did not expect %s' % el . tag ) def _merge_lists ( ilvl , current_ilvl , ol_dict , current_ol ) : for i in reversed ( range ( ilvl , current_ilvl ) ) : # Any list that is more indented that ilvl needs to # be merged to the list before it. if i not in ol_dict : continue if ol_dict [ i ] is not current_ol : if ol_dict [ i ] is current_ol : continue ol_dict [ i ] [ - 1 ] . append ( current_ol ) current_ol = ol_dict [ i ] # Clean up finished nested lists. for key in list ( ol_dict ) : if key > ilvl : del ol_dict [ key ] return current_ol for li_node in li_nodes : w_namespace = get_namespace ( li_node , 'w' ) if not is_li ( li_node , meta_data ) : # Get the content and visited nodes new_el , el_visited_nodes = _build_non_li_content ( li_node , meta_data , ) list_contents . append ( new_el ) visited_nodes . extend ( el_visited_nodes ) continue if list_contents : li_el = _build_li ( list_contents ) list_contents = [ ] current_ol . append ( li_el ) # Get the data needed to build the current list item list_contents . append ( get_element_content ( li_node , meta_data , ) ) ilvl = get_ilvl ( li_node , w_namespace ) numId = get_numId ( li_node , w_namespace ) list_type = get_ordered_list_type ( meta_data , numId , ilvl ) # If the ilvl is greater than the current_ilvl or the list id is # changing then we have the first li tag in a nested list. We need to # create a new list object and update all of our variables for keeping # track. if ( ilvl > current_ilvl ) or ( numId != current_numId ) : # Only create a new list ol_dict [ ilvl ] = create_list ( list_type ) current_ol = ol_dict [ ilvl ] current_ilvl = ilvl current_numId = numId # Both cases above are not True then we need to close all lists greater # than ilvl and then remove them from the ol_dict else : # Merge any nested lists that need to be merged. current_ol = _merge_lists ( ilvl = ilvl , current_ilvl = current_ilvl , ol_dict = ol_dict , current_ol = current_ol , ) # Set the root list after the first list is created. if root_ol is None : root_ol = current_ol # Set the current list. if ilvl in ol_dict : current_ol = ol_dict [ ilvl ] else : # In some instances the ilvl is not in the ol_dict, if that is the # case, create it here (not sure how this happens but it has # before.) Only do this if the current_ol is not the root_ol, # otherwise etree will crash. if current_ol is not root_ol : # Merge the current_ol into the root_ol. _merge_lists is not # equipped to handle this situation since the only way to get # into this block of code is to have mangled ilvls. root_ol [ - 1 ] . append ( current_ol ) # Reset the current_ol current_ol = create_list ( list_type ) # Create the li element. visited_nodes . extend ( list ( li_node . iter ( ) ) ) # If a list item is the last thing in a document, then you will need to add # it here. Should probably figure out how to get the above logic to deal # with it. if list_contents : li_el = _build_li ( list_contents ) list_contents = [ ] current_ol . append ( li_el ) # Merge up any nested lists that have not been merged. current_ol = _merge_lists ( ilvl = 0 , current_ilvl = current_ilvl , ol_dict = ol_dict , current_ol = current_ol , ) return root_ol , visited_nodes
Build the list structure and return the root list
Build the list structure and return the root list