2011-06-16 100 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。