XPath to find nearest ancestor element that contains an element that has an attribute with a certain value

前端 未结 4 1014
轻奢々
轻奢々 2020-12-28 14:31

ancestor::foo[bar[@attr=\"val\"]]

I thought this would work, but it\'s not. I need to find the nearest foo element going up in the tree tha

4条回答
  •  北海茫月
    2020-12-28 14:45

    If you have a file like this:

                                                                                                                 
                                                                                                           
                                                                                                           
                                                                                                     
                                                                                                                 
                                                                                                           
                                                                                                     
                                                                                                                 
                                                                                                           
                                                                                                                  
                                                                                                     
                                                                                                                 
                                                                                                                 
                                                                                                                 
    
    

    and you want the foo nodes with the ids 2 and 3, i.e. the closest foos to their bar descendants having attr=val, the following works:

    //foo[descendant::bar[@attr="val"] and not(descendant::foo)]
    

    If you omit and not(descendant::foo) you get additionally the foo with the id 0.

    The other answers didn't work for me on the general case of my example.

    You can test it in Python with:

    from lxml import etree
    tree = etree.parse('example.xml')
    foos = tree.xpath('//foo[descendant::bar[@attr="val"] and not(descendant::foo)]')
    for foo in foos:
        print(foo.attrib)
    

    which prints:

    {'id': '2'}
    {'id': '3'}
    

    Notice that the xpath used is not efficient. I would love to learn a more efficient one.

提交回复
热议问题