| 1 | from lxml import html |
| 2 | def get_xpath_top_down(element: html.HtmlElement, id_column: str='temp_id', label_column: str='temp_clickable_label', path: str='', order: int=0, |
| 3 | in_svg: bool=False, temp_id: int=0) -> tuple[int, dict[str, str], dict[str]]: |
| 4 | used_labels, i2xpath = {}, {} |
| 5 | # path |
| 6 | tag = element.tag.lower() |
| 7 | in_svg = in_svg or (tag == 'svg') |
| 8 | |
| 9 | if not in_svg and 'id' in element.attrib: |
| 10 | node_id = element.attrib['id'] |
| 11 | path = f'//*[@id="{node_id}"]' |
| 12 | else: |
| 13 | suffix = f'[{order}]' if order > 0 else '' |
| 14 | prefix = f'*[name()="{tag}"]' if in_svg else tag |
| 15 | path = path + '/' + prefix + suffix |
| 16 | |
| 17 | # add temp id |
| 18 | element.attrib[id_column] = str(temp_id) |
| 19 | ori_label = element.attrib.get(label_column, '') |
| 20 | if ori_label != '': |
| 21 | used_labels[ori_label] = True |
| 22 | |
| 23 | bid = str(temp_id) |
| 24 | i2xpath[bid] = path |
| 25 | i2xpath[path] = bid |
| 26 | i2xpath[f'xpath/{path}'] = bid |
| 27 | i2xpath[f'xpath=/{path}'] = bid |
| 28 | |
| 29 | temp_id += 1 |
| 30 | |
| 31 | # traverse node |
| 32 | children = element.getchildren() |
| 33 | tag_dict = {} |
| 34 | id_list = [] |
| 35 | for child in children: |
| 36 | ctag = child.tag.lower() |
| 37 | if ctag not in tag_dict: |
| 38 | tag_dict[ctag] = 0 |
| 39 | tag_dict[ctag] += 1 |
| 40 | id_list.append(tag_dict[ctag]) |
| 41 | |
| 42 | for cid, child in zip(id_list, children): |
| 43 | ctag = child.tag.lower() |
| 44 | cod = cid if tag_dict[ctag] > 1 else 0 |
| 45 | temp_id, i2x, ulabels = get_xpath_top_down(child, id_column, label_column, path, cod, in_svg, temp_id) |
| 46 | i2xpath.update(i2x) |
| 47 | used_labels.update(ulabels) |
| 48 | |
| 49 | return temp_id, i2xpath, used_labels |
| 50 | |
| 51 | def print_html_object(obj: str='') -> str: |
| 52 | tab_cnt = 0 |