在XML文件中搜索字符串并在菜单树中打印位置-Python

时间:2018-10-25 08:45:03

标签: python

我有一个包含菜单结构的xml文件。我要搜索菜单名称或应用程序名称,如果匹配,则要在树中打印完整路径。

这是xml文件的一部分:

  <menu name="main_menu" display="Main Menu">
    <menu name="A" display="A" 
      <menu name="X" display="X" >
        <application name="M" display="M"/>
        <application name="N" display="N"/>
      </menu>
    <menu name="B" display="B" 
      <menu name="Y" display="Y" >
        <application name="O" display="O"/>
        <application name="P" display="P"/>
      </menu>

我正在尝试按XML文件中匹配的名称搜索并打印位置。例如:

如果我搜索"P",它将打印"B", "Y", "P"

或者如果我搜索"Y",它将打印"B", "Y"

到目前为止,我已经尝试过:

def findLocation(name):
    xmlLocation = "menu.xml"

    tree = ET.parse(xmlLocation)
    root = tree.getroot()
    parent_map = {c:p for p in tree.iter() for c in p} 
    for item in tree.iterfind('.//menu/..'):
        if item.find('menu').text.encode('utf-8') == name:
            print parent_map[item].find('name').text

findLocation("Y")

但是它什么也没打印。您能建议我该怎么做吗?

1 个答案:

答案 0 :(得分:1)

您可以使用类似这样的功能(递归,但对于深度受限制的xml来说是可以的):

def find_location(tree, target):
    stack = []
    root = tree.getroot()

    def helper(child):  # recursive part
        name = dict(child.items())['name']
        if name == 'target':
            return [name]
        children = child.getchildren()
        for c in children:
            ret = helper(c)
            if ret and ret[-1] == target:
                return [name] + ret
        return [name]
    # you can cahnge it if you need it, for instance, if only "Main Menu" parsing required
    for child in root:
        result = helper(child)
        if result and result[-1] == target:
            return result
    return [] 

用法:

tree = ET.parse("menu.xml")
location = find_location(tree, 'M')
print(location)
Out:
['main_menu', 'A', 'X', 'M']

location = find_location(tree, 'N')
print(location)
Out:
['main_menu', 'A', 'X', 'N']

location = find_location(tree, 'Y')
print(location)
Out:
['main_menu', 'B', 'Y']

location = find_location(tree, 'P')
print(location)
Out:
['main_menu', 'B', 'Y', 'P']

location = find_location(tree, 'Z')  # no such name in XML
print(location)
Out:
[]  

注意:如果目标名称中有多个元素,则此代码将返回第一次出现的情况。

您可以轻松采用此方法,也可以仅裁剪列表中的第一个元素,然后打印输出:

for node in location[1:]:
    print(node)

Out:
'B'
'Y' 
'P'

我已经使用了这样的xml(经过精心修改,因为该内容来自发布后的问题):

<?xml version="1.0"?>
<data>
    <menu name="main_menu" display="Main Menu">
    <menu name="A" display="A" >
      <menu name="X" display="X" >
        <application name="M" display="M"/>
        <application name="N" display="N"/>
      </menu>
    </menu>
    <menu name="B" display="B" >
      <menu name="Y" display="Y" >
        <application name="O" display="O"/>
        <application name="P" display="P"/>
      </menu>
    </menu>
    </menu>
</data>