2011-06-16 50 views
1

我对Python和编程有点新,所以非常抱歉。顺便提一下,在此先感谢。Xml使用递归解析Python。返回值的问题

我解析使用Python 2.5,cElementTree和外籍的XML文档(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) 

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

回答

5

递归要注意你的基地的情况下,你的递归情况。 无论您的基本情况如何,如果您希望能够从您的递归收集信息,他们必须返回您的递归案例可以(并且更重要的是)使用的数据。同样,你需要确保你的递归情况返回的数据可以被对方使用。

首先确定你的基地和递归的情况。 基本情况是“叶”节点,没有孩子。在基本情况下,您只想返回一些数据,而不是再次调用递归函数。这就是允许你像他们说的那样得到“备份堆栈”,并防止无限递归。 递归案例将要求您保存从一系列递归调用收集的数据,这几乎就是您在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) 
+0

非常感谢您的周到和彻底的回应。我在我的代码中试过了,它效果很好。现在,只是为了提高我对递归 – 9monkeys 2011-06-17 18:42:55

+0

@ 9monkeys的理解:如果您赞成回复,请将其投票并单击上下投票按钮旁边的复选标记(使其变为绿色)。这将使人们看到这是一个有用的回应,以供将来参考,(也给我一些代表点。:) – 2011-06-17 21:54:53

+0

是的,的确。需要学习如何使用这个东西:) – 9monkeys 2011-06-20 20:50:55

0

你不是与递归调用的结果做任何事情时,该节点是searchNode。

您需要聚合递归调用的结果,一个节点的孩子或只是使用打印child.text,而不是回报child.text。