如何使用python获取xml文件中的特定节点

时间:2010-02-09 16:29:56

标签: python xml

我正在寻找一种从非常大的xml文档中获取特定标签的方法 用python dom内置模块
例如:

<AssetType longname="characters" shortname="chr" shortnames="chrs">
  <type>
    pub
  </type>
  <type>
    geo
  </type>
  <type>
    rig
  </type>
</AssetType>

<AssetType longname="camera" shortname="cam" shortnames="cams">
  <type>
    cam1
  </type>
  <type>
    cam2
  </type>
  <type>
    cam4
  </type>
</AssetType>

我想检索获得属性的AssetType节点的子节点的值(longname =“characters”) 得到'pub','geo','rig'的结果 请记住,我有超过1000&lt; AssetType&GT;节点
提前谢谢

6 个答案:

答案 0 :(得分:5)

假设您的文档名为assets.xml并具有以下结构:

<assets>
    <AssetType>
        ...
    </AssetType>
    <AssetType>
        ...
    </AssetType>
</assets>

然后您可以执行以下操作:

from xml.etree.ElementTree import ElementTree
tree = ElementTree()
root = tree.parse("assets.xml")
for assetType in root.findall("//AssetType[@longname='characters']"):
    for type in assetType.getchildren():
        print type.text

答案 1 :(得分:3)

您可以使用pulldom API来处理解析大文件,而无需立即将其全部加载到内存中。这提供了比使用SAX更方便的界面,只有轻微的性能损失。

它基本上允许您流式传输xml文件,直到找到您感兴趣的位,然后在此之后开始使用regular DOM operations


from xml.dom import pulldom

# http://mail.python.org/pipermail/xml-sig/2005-March/011022.html
def getInnerText(oNode):
    rc = ""
    nodelist = oNode.childNodes
    for node in nodelist:
        if node.nodeType == node.TEXT_NODE:
            rc = rc + node.data
        elif node.nodeType==node.ELEMENT_NODE:
            rc = rc + getInnerText(node)   # recursive !!!
        elif node.nodeType==node.CDATA_SECTION_NODE:
            rc = rc + node.data
        else:
            # node.nodeType: PROCESSING_INSTRUCTION_NODE, COMMENT_NODE, DOCUMENT_NODE, NOTATION_NODE and so on
           pass
    return rc


# xml_file is either a filename or a file
stream = pulldom.parse(xml_file) 
for event, node in stream:
    if event == "START_ELEMENT" and node.nodeName == "AssetType":
        if node.getAttribute("longname") == "characters":
            stream.expandNode(node) # node now contains a mini-dom tree
            type_nodes = node.getElementsByTagName('type')
            for type_node in type_nodes:
                # type_text will have the value of what's inside the type text
                type_text = getInnerText(type_node)

答案 2 :(得分:2)

使用xml.sax模块。构建自己的处理程序,在startElement内部,您应该检查名称是否为AssetType。这样,您应该只能在处理AssetType节点时执行操作。

Here你有示例处理程序,它显示了如何构建一个(虽然它不是最漂亮的方式,在那一点上我不知道Python的所有很酷的技巧; - ))。

答案 3 :(得分:2)

如果您不介意将整个文档加载到内存中:

from lxml import etree
data = etree.parse(fname)
result = [node.text.strip() 
    for node in data.xpath("//AssetType[@longname='characters']/type")]

您可能需要删除代码开头的空格才能使其正常工作。

答案 4 :(得分:1)

您可以使用xpath,例如“// AssetType [longname ='characters'] / xyz”。

对于Python中的XPath库,请参阅http://www.somebits.com/weblog/tech/python/xpath.html

答案 5 :(得分:1)

与eswald的解决方案类似,再次剥离空白,再次将文档加载到内存中,但一次返回三个文本项

from lxml import etree

data = """<AssetType longname="characters" shortname="chr" shortnames="chrs"
  <type>
    pub
  </type>
  <type>
    geo
  </type>
  <type>
    rig
  </type>
</AssetType>
"""

doc = etree.XML(data)

for asset in doc.xpath('//AssetType[@longname="characters"]'):
  threetypes = [ x.strip() for x in asset.xpath('./type/text()') ]
  print threetypes