python xml查询得到父

时间:2011-03-21 04:45:48

标签: python xml xpath

我有一个大的xml文档,如下所示:

<Node name="foo">
    <Node name="16764764625">
        <Val name="type"><s>3</s></Val>
        <Val name="owner"><s>1</s></Val>
        <Val name="location"><s>4</s></Val>
        <Val name="brb"><n/></Val>
        <Val name="number"><f>24856</f></Val>
        <Val name="number2"><f>97000.0</f></Val>
    </Node>
    <Node name="1764466544">
        <Val name="type"><s>1</s></Val>
        <Val name="owner"><s>2</s></Val>
        <Val name="location"><s>6</s></Val>
        <Val name="brb"><n/></Val>
        <Val name="number"><f>265456</f></Val>
        <Val name="number2"><f>99000.0</f></Val>
    </Node>
    ...
</Node>

我的任务是通过搜索找到节点Val name =“number”的子元素是否包含265456

来获取父节点的值:1764466544(第二节点中的名称值)

我一直在XPath和ElementTree上做一堆阅读,但我仍然不确定从哪里开始实际查询。寻找示例......我找不到任何引用父节点的结果。

仍然是python的新手......任何建议都会受到赞赏。

由于

4 个答案:

答案 0 :(得分:4)

不幸的是,在使用ElementTree API时,每个Element对象都没有返回其父级的引用,因此您无法从已知点上升树。相反,您必须找到可能的父对象并过滤您想要的对象。

这通常用XPath表达式完成。但是,ElementTree只支持XPath的一个子集(see the docs),其中最有用的部分仅在ElementTree 1.3中添加,后者仅附带Python 2.7+或3.2 +。

甚至,ElementTree的XPath它不能用你的文件 - 没有办法根据节点的文本,只有它的属性(或属性值)进行选择。

我的实验只发现了两种可以继续使用ElementTree的方法。如果您使用的是Python 2.7+(或者能够下载并安装较新版本的ElementTree以使用较旧的Python版本),可以修改XML文件的格式以将数字设置为属性,如此

<Val name="number"><f val="265456" /></Val>

然后以下Python代码将拉出感兴趣的节点:

import xml.etree.ElementTree as ETree
tree = ETree.ElementTree(file='sample.xml')
nodes = tree.findall(".//Node/Val[@name='number']/f[@val='265456']....")

对于较旧的Pythons,或者如果您无法修改XML格式,则必须手动过滤无效节点。以下对我有用:

import xml.etree.ElementTree as ETree
tree = ETree.ElementTree(file='sample.xml')
all = tree.findall(".//Node")
nodes = []

# Filter matching nodes and put them in the nodes variable.
for node in all:
    for val in node.getchildren():
        if val.attrib['name'] == 'number' and val.getchildren()[0].text =='265456':
            nodes.append(node)

这些解决方案都不是我称之为理想的解决方案,但它们是我能够使用ElementTree库的唯一解决方案(因为这是您提到的)。您可能最好使用第三方库而不是使用内置库;请参阅the Python wiki entry on XML以获取选项列表。 lxml是广泛使用的libxml2库的Python绑定,并且是我建议首先查看的那个。它具有XPath支持,因此您应该能够使用其他答案中的查询。

答案 1 :(得分:3)

这个XPath:

/Node/Node[Val[@name='number']/f='265456']/@name

输出:

1764466544

答案 2 :(得分:0)

以下功能在类似情况下帮助了我。正如文档字符串所解释的那样,它在一般情况下不起作用,但如果您的节点是唯一的,它应该会有所帮助。

def get_element_ancestry(root, element):
'''Return a list of ancestor Elements for the given element.

If both root and element are of type xml.etree.ElementTree.Element, and if
the given root contains the given element as a descendent, then return a
list of direct xml.etree.ElementTree.Element ancestors, starting with root
and ending with element. Otherwise, return an empty list.

The xml.etree.ElementTree module offers no function to return the parent of
a given Element, presumably because an Element may be in more than one tree,
or even multiple times within a given tree, so its parent depends on the
context. This function provides a solution in the specific cases where the
caller either knows that the given element appears just once within the
tree or is satisfied with the first branch to reference the given element.
'''
result = []
xet = xml.etree.ElementTree
if not xet.iselement(root) or not xet.iselement(element):
    return result
xpath = './/' + element.tag \
    + ''.join(["[@%s='%s']" % a for a in element.items()])
parent = root
while parent != None:
    result.append(parent)
    for child in parent.findall('*'):
        if child == element:
            result.append(element)
            return result
        if child.findall(xpath).count(element):
            parent = child
            break
    else:
        return []
return result

答案 3 :(得分:-2)

通常

node.parentNode 

会将一个potiner返回给父节点(使用DOM解析器时)。

对于XPath,请参阅

http://www.tizag.com/xmlTutorial/xpathparent.php