Houy Narun
Houy Narun

Reputation: 1725

How to Generate Order List Item from List in python

I tried to create an order list item (<ol></ol>) from a list in python. My list is as following:

listItem = [    
            ['101','Dashboard'],
            ['102','Potential Customer'],
            ['102-01','Potential Customer Activity'],
            ['102-02','Potential Customer Report'],
            ['102-99','Potentail Customer Detail'],
            ['102-99-01','Potential Customer Detail Listing'],
            ['102-99-02','Potential Customer Follow Up'],
            ['102-99-02-01','Follow Up PAR']
        ]

From this list, I wish to make it as order list item according to itemID such as 101,102,102-01,..etc that would like this:

<ol>
    <li data-itemID="101">Dashboard</li>
    <li data-itemID="102">Potential Customer
        <ol>
            <li data-itemID="102-01">Potential Customer Activity</li>
            <li data-itemID="102-99">Potential Customer Detail
                <ol>
                    <li data-itemID="102-99-01">Potential Customer Detail Listing</li>
                    <li data-itemID="102-99-02">Potential Customer Follow Up
                        <ol>
                            <li data-itemID="102-99-02-01">Follow Up PAR</li>
                        </ol>
                    </li>
                </ol>
            </li>
        </ol>
    <li>
<ol>

I have tried my code as following:

from flask import *
import re

app = Flask(__name__)


@app.route('/', methods=['GET','POST'])
def checkName():

    orderList = ''
    listItem = [    
                ['101','Dashboard'],
                ['102','Potential Customer'],
                ['102-01','Potential Customer Activity'],
                ['102-02','Potential Customer Report'],
                ['102-99','Potentail Customer Detail'],
                ['102-99-01','Potential Customer Detail Listing'],
                ['102-99-02','Potential Customer Follow Up'],
                ['102-99-02-01','Follow Up PAR']
            ]
    print "List Item: ",listItem
    orderList += '<ol>'
    for item in listItem:
        if item[0].find('-') > 0:
            # list has sub-list item
            orderList += '<ol>'
            orderList += '<li data-itemID=%s>'%(item[0])
            orderList += item[1]
            orderList += '</li>'
            orderList += '</ol>'
        else:
            # list has no sub-list item
            orderList += '<li data-itemID=%s>'%(item[0])
            orderList += item[1]
            orderList += '</li>'

    orderList += '</ol>'

    return render_template('home.html', orderList=orderList)

if __name__ == '__main__':

    app.run(debug=True)

home.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Home Page</title>
</head>
<body>
    {% if orderList %}
        {{ orderList | safe }}
    {% else %}
        <p>Please select a list menu</p>
    {% endif %}
</body>
</html>

However, the generated order list is not as what I expected from above, it does not has a correct sub-order list at all. In stead, it results like this:

1. Dashboard
2. Potential Customer
   1. Potential Customer Activity
   1. Potential Customer Report
   1. Potentail Customer Detail
   1. Potential Customer Detail Listing
   1. Potential Customer Follow Up
   1. Follow Up PAR

How can I correct my code to achieve result as I expected above? Thanks.

Upvotes: 0

Views: 508

Answers (2)

ryanmrubin
ryanmrubin

Reputation: 728

The code here assumes that, while it iterates through listItem, every time it encounters an item with a dash in the data ID, then a new OL should be started. That's not what you want, though.

For a structure like this, I lean towards a recursive algorithm to handle the subsidiary items (which helps avoid assumptions like the one above). I don't know your edge cases, but something like this might work for you:

# somewhere else in your codebase, let's say utils.py

import copy


def structure_listitem(listitem):
    items = copy.deepcopy(listitem)

    if not items:
        return items

    if len(items) == 1:
        items[0].append([])
        return items

    first, rest = items[0], items[1:]

    header = first[0]
    sub_items = []
    while rest and rest[0][0].startswith(header):
        sub_items.append(rest.pop(0))

    first.append(structure_listitem(sub_items))
    return [first] + structure_listitem(rest)


def render_structured_listitem(listitem):
    if not listitem:
        return ''

    out = ['<ol>']
    for item in listitem:
        the_id, header, sublist = item
        if sublist:
            out.append('<li data-itemID="%s">%s\n%s\n</li>'
                       % (the_id, header, render_structured_listitem(sublist)))
        else:
            out.append('<li data-itemID="%s">%s</li>'
                       % (the_id, header))

    out.append('</ol>')
    return '\n'.join(out)


def render_listitem(listitem):
    return render_structured_listitem(structure_listitem(listitem))    

and then, in the app code:

from utils import render_listitem # or from wherever

# ...

@app.route('/', methods=['GET','POST'])
def check_name():
    listitem = [    
                ['101','Dashboard'],
                ['102','Potential Customer'],
                ['102-01','Potential Customer Activity'],
                ['102-02','Potential Customer Report'],
                ['102-99','Potentail Customer Detail'],
                ['102-99-01','Potential Customer Detail Listing'],
                ['102-99-02','Potential Customer Follow Up'],
                ['102-99-02-01','Follow Up PAR']
    ]    

    ordered_list = render_listitem(listitem)

    return render_template('home.html', ordered_list=ordered_list)

Upvotes: 1

Samir Sadek
Samir Sadek

Reputation: 1690

If you do not mind to go with a not well formed HTML (I am not closing the <ol> you can have this solution. To have a fully compliant HTML a little work in the same direction would be needed.

flask_file.py

from flask import *
import re

app = Flask(__name__)


itid = lambda x: x[0]
itval = lambda x: x[1]
last = lambda x: x[-1]

def wrapit(it_id):
    return '<li item-id="%s">' % it_id

def wrapval(id_val):
    return '%s</li>' % id_val

def put_ol(it_id):
    return last(it_id.split('-')) == '01'

@app.route('/', methods=['GET','POST'])
def checkName():
    listItem = [
                ['101','Dashboard'],
                ['102','Potential Customer'],
                ['102-01','Potential Customer Activity'],
                ['102-02','Potential Customer Report'],
                ['102-99','Potentail Customer Detail'],
                ['102-99-01','Potential Customer Detail Listing'],
                ['102-99-02','Potential Customer Follow Up'],
                ['102-99-02-01','Follow Up PAR']
            ]
    orderItem = []

    for item in listItem:
        if put_ol(itid(item)):
            orderItem.append('<ol>')
        orderItem.append(wrapit(itid(item)))
        orderItem.append(wrapval(itval(item)))

    print("List Item: %s " % listItem)

    return render_template('home.html', orderItem=orderItem)

if __name__ == '__main__':

    app.run(debug=True)

home.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Home Page</title>
</head>
<body>
<ol>
{% for item in orderItem %}
        {{ item | safe }}
    {% endfor %}
</ol>
</body>
</html>

Upvotes: 0

Related Questions