Skip to main content
 首页 » 编程设计

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

2025年05月04日17kuangbin

我对 Python 和一般编程有些陌生,所以我深表歉意。顺便说一句,提前致谢。

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

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

“地标”节点的示例 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 网站上,但我认为这更像是一个一般的编程问题。有任何想法吗?

请您参考如下方法:

对于递归,您需要关注基本情况和递归情况。 无论您的基本案例是什么,如果您希望能够从递归中收集信息,它们就必须返回您的递归案例可以(更重要的是)使用的数据。同样,您需要确保递归案例返回的数据可以被彼此使用。

首先确定您的基础和递归案例。 基本情况是“叶”节点,没有子节点。在基本情况下,您只想返回一些数据,而不是再次调用递归函数。正如他们所说,这就是让您“备份堆栈”并防止无限递归的原因。 递归情况将要求您保存从一系列递归调用中收集的数据,这几乎就是您在 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)