使用递归的Python解析Xml。返回值有问题

时间:2011-06-16 20:42:44

标签: python xml recursion

我对Python和编程有点新,所以我道歉。顺便说一句,提前谢谢。

我正在使用Python 2.5,cElementTree和expat解析xml文档(特别是在Google Earth中使用的kml)。我试图从每个几何类型(即折线,多边形,点)的每个“地标”节点内的“名称”,“描述”和“坐标”节点中拉出所有文本,但我想保留几何类型分离。例如,对于作为“多边形”一部分的每个地标,我只想要“名称”,“描述”和“坐标”文本(即它具有“多边形”节点)。我还需要为'折线'和'点'做这个。我已经找到了一种方法来做到这一点,但是代码很长并且特定于每种几何类型,这引出了我的问题。

理想情况下,我想为每种几何类型使用相同的代码,但问题是每种几何类型都有不同的节点结构(即不同的节点名称和嵌套节点的数量)。因此,为了概念验证,我认为这将是一个使用/学习递归来深入挖掘'placemark'节点的节点树并获取我正在寻找的信息的好机会。我已经查看了许多关于Python递归的帖子,并且仍然遇到了实现所提供解决方案的问题。

'placemark'节点的示例xml是:

 <Placemark>
    <name>testPolygon</name>
    <description>polygon text</description>
    <styleUrl>#msn_ylw-pushpin</styleUrl>
    <Polygon>
            <tessellate>1</tessellate>
            <outerBoundaryIs>
                    <LinearRing>
                            <coordinates>
                                    -81.4065,31.5072,0 -81.41269,31.45992,0 -81.34490,31.459696,0 
                            </coordinates>
                    </LinearRing>
            </outerBoundaryIs>
    </Polygon>
 </Placemark>

我使用的递归函数是:

def getCoords( child, searchNode ):

    # Get children of node
    children = child.getchildren()

    # If node has one or more child
    if len( children ) >= 1 :

        # Loop through all the children
        for child in children:

            # call to recursion function
            getCoords( child, searchNode )

    # If does not have children and is the 'searchNode'
    elif len( children ) == 0 and child.tag == searchNode:

        # Return the text inside the node. This is where it is not working    
        # Other posts recommended returning the function like 
        # return getCoords(child, searchNode), but I am getting an unending loop
        return child.text

    # Do nothing if node doesn't have children and does not match 'searchNode'    
    else: 

        print 'node does not have children and is not what we are looking for'

我正在调用递归函数,如:

searchNode = 'coordinates'

# loop through all 'Placemark nodes' in document
for mark in placemark:

    # Get children of 'Placemark' node
    children = mark.getchildren() 

    # Loop through children nodes
    for child in children:

        # if a 'Polygon' node is found
        if child.tag == 'Polygon':

            # call recursion function
            getCoords( child, searchNode)

我知道,至少,我的问题的一部分是返回值。其他帖子建议返回函数,我将其解释为'return getCoords(child,searchNode),但我得到一个无休止的循环。此外,我意识到这可以发布在GIS网站上,但我认为这更像是一个普通的编程问题。有任何想法吗?

2 个答案:

答案 0 :(得分:6)

通过递归,您需要关注基本案例和递归案例。 无论您的基本情况如何,如果您希望能够从递归中收集信息,他们必须返回您的递归案例可以(更重要的是)使用的数据。同样,您需要确保递归案例返回的数据可以相互使用。

首先确定您的基础和递归案例。 基本案例是“叶子”节点,没有子节点。在基本情况下,您只想返回一些数据,而不是再次调用递归函数。这就是允许你按照他们的说法“备份堆栈”并阻止无限递归的原因。 递归情况将要求您保存从一系列递归调用中收集的数据,这几乎就是您在for循环中所做的事情。

我注意到你有

# Recursive case: node has one or more child
if len( children ) >= 1 :
    # Loop through all the children
    for child in children:
        # call to recursion function
        getCoords( child, searchNode )

但是你对getCoords调用的结果做了什么?

您要么想要将结果保存在某种数据结构中,您可以在for循环结束时返回该数据结构,或者如果您对保存结果本身不感兴趣,只需打印基础案例1(成功当你到达它而不是返回它时。因为现在你的基础案例1只是将堆栈返回到一个没有对结果做任何事情的实例!所以试试:

# If node has one or more child
if len( children ) >= 1 :
    # Data structure for your results
    coords = []
    # Loop through all the children
    for child in children:
        # call to recursion function
        result = getCoords( child, searchNode )
        # Add your new results together
        coords.extend(result)
    # Give the next instance up the stack your results!
    return coords

现在,由于您的结果位于列表中并且您正在使用extend()方法,因此您必须使基本案例返回列表!

# Base case 1: does not have children and is the 'searchNode'
elif len( children ) == 0 and child.tag == searchNode:
    # Return the text from the node, inside a list
    return [child.text]
# Base case 2: doesn't have children and does not match 'searchNode'
else:
    # Return empty list so your extend() function knows what to do with the result
    return []

这应该只给你一个列表,你可能想要存储在一个变量中。我刚刚在这里打印了结果:

searchNode = 'coordinates'
# loop through all 'Placemark nodes' in document
for mark in placemark:
    # Get children of 'Placemark' node
    children = mark.getchildren()
    # I imagine that getchildren() might return None, so check it
    # otherwise you'll get an error when trying to iterate on it
    if children:
        # Loop through children nodes
        for child in children:
            # if a 'Polygon' node is found
            if child.tag == 'Polygon':
                # call recursion function and print (or save) result
                print getCoords( child, searchNode)

答案 1 :(得分:0)

当节点是searchNode时,你没有对递归调用的结果做任何事情。

您需要将递归调用的结果聚合到节点的子节点,或者只使用print child.text而不是return child.text。