2011-03-21 3 views
1

나는 다음과 같습니다 큰 XML 문서를 가지고 :파이썬 XML 쿼리 GET 부모

<Node name="foo"> 
    <Node name="16764764625"> 
     <Val name="type"><s>3</s></Val> 
     <Val name="owner"><s>1</s></Val> 
     <Val name="location"><s>4</s></Val> 
     <Val name="brb"><n/></Val> 
     <Val name="number"><f>24856</f></Val> 
     <Val name="number2"><f>97000.0</f></Val> 
    </Node> 
    <Node name="1764466544"> 
     <Val name="type"><s>1</s></Val> 
     <Val name="owner"><s>2</s></Val> 
     <Val name="location"><s>6</s></Val> 
     <Val name="brb"><n/></Val> 
     <Val name="number"><f>265456</f></Val> 
     <Val name="number2"><f>99000.0</f></Val> 
    </Node> 
    ... 
</Node> 

내 임무는 부모 노드의 값을 얻을 수 있습니다 다음을 수행하여 1,764,466,544 (2 노드의 이름 값) 검색 노드 이름의 하위 요소가 "number"인지 확인합니다. 265456

XPath 및 ElementTree에서 읽는 힙을 수행했지만 실제로 쿼리를 시작할 위치가 아직 확실하지 않습니다. 예제를 찾는 중 ... 결과로 상위 노드를 찾을 수 없습니다.

아직 새로운 python .. 모든 제안을 주시면 감사하겠습니다. (A DOM 파서를 사용하는 경우)

감사

답변

3

참조하십시오 :

/Node/Node[Val[@name='number']/f='265456']/@name 

출력 다음 ElementTree API를 사용할 때 불행하게도

1764466544 
+0

@itwb - 필자는 Python에서 XPath를 시도한 적이 없으므로, 그 부분은 당신에게 달려 있지만 위의 XPath는 추상으로 작동합니다. 예를 들면 다음과 같습니다. http://www.xmlme.com/XpathTool.aspx –

+0

그래, 고마워. 이제이 오류가 발생합니다 : SyntaxError : 요소의 절대 경로를 사용할 수 없습니다. – itwb

+0

여기선 익숙하지 않은 지역이지만 [이 링크] (http://nltk.googlecode.com/svn/trunk/doc/api/nltk.etree.ElementPath-pysrc.html)에서는 XPath 표현식에 대해 다음 코드를 보여줍니다. '/':'SyntaxError ("요소에 절대 경로를 사용할 수 없습니다")를 발생시킵니다. 어쩌면 상대적인 표현을 시도할까요? 이 'Node/Node [Val [@ name ='number ']/f ='265456 ']/@ name' 또는이'Node/Node [Val [@ 이름 ='번호 ']/f ='265456 ' ]/@ name' –

3

는, 각 Element 오브젝트가 참조를 다시이 없습니다 그 부모에게, 그래서 당신은 c 주석은 알려진 지점에서 나무 위로 올라갑니다. 대신 가능한 상위 개체를 찾아 원하는 개체를 필터링해야합니다.

이것은 일반적으로 XPath 식으로 수행됩니다. 그러나 ElementTree는 XPath (see the docs)의 하위 집합 만 지원하며 가장 유용한 부분은 ElementTree 1.3에만 추가되었으며 Python 2.7 이상 또는 3.2 이상에서만 제공됩니다.

심지어 ElementTree의 XPath는 파일을 그대로 사용할 수 없습니다. 노드의 텍스트를 기반으로 선택할 수있는 방법이 없으며 속성 (또는 속성 값) 만 선택할 수 있습니다.

내 실험에서 ElementTree로 진행할 수있는 두 가지 방법 만 발견했습니다. Python 2.7 이상을 사용하고 있거나 (최신 Python 버전의 ElementTree를 다운로드하여 설치할 수있는 경우) 과 같이 XML 파일 형식을 수정하여 숫자를 속성으로 지정할 수 있습니다 (예 :

). 이전의 파이를 들어

import xml.etree.ElementTree as ETree 
tree = ETree.ElementTree(file='sample.xml') 
nodes = tree.findall(".//Node/Val[@name='number']/f[@val='265456']....") 

를, 또는 XML 형식을 변경할 수없는 경우, 수동으로 유효하지 않은 노드를 필터링해야합니다 :

<Val name="number"><f val="265456" /></Val> 

다음 파이썬 코드는 관심있는 노드를 가져옵니다 .즉 당신이 무엇 때문에

import xml.etree.ElementTree as ETree 
tree = ETree.ElementTree(file='sample.xml') 
all = tree.findall(".//Node") 
nodes = [] 

# Filter matching nodes and put them in the nodes variable. 
for node in all: 
    for val in node.getchildren(): 
     if val.attrib['name'] == 'number' and val.getchildren()[0].text =='265456': 
      nodes.append(node) 

어느 이러한 솔루션의

내가 이상적이라고 부르는,하지만 그들은 내가합니다 (ElementTree 라이브러리 작업을 할 수 있었던 유일한 사람이야 다음은 나를 위해 일한 다음 언급 한 사용). 내장 된 라이브러리를 사용하는 대신 제 3 자 라이브러리를 사용하는 것이 더 나을 수도 있습니다. 옵션 목록은 the Python wiki entry on XML을 참조하십시오. lxml은 널리 사용되는 libxml2 라이브러리를위한 파이썬 바인딩이며, 처음에 살펴볼 것이 좋습니다. XPath가 지원되므로 다른 답변의 쿼리를 사용할 수 있어야합니다.

+0

Python이 일부 XPath 지원을 추가했다는 것에 정말 짜증나지만 ".."구문을 사용하여 현재 노드에서 위로 이동할 수 없습니다. Python [documentation] (https://docs.python.org/2.7/library/xml.etree.elementtree.html)에 기술되어 있어야합니다. 사실 [documentation] (https://docs.python.org/2.7/library/xml.etree.elementtree.html)에는이 구문이 지원된다고 나와 있습니다. 현재 요소 위로 이동하지 않는 한 지원됩니다. "사람/.."? 왜 이것이 작동하지 않는지 알아 내려고 한시간을 보냈습니다. – Samuel

0

다음과 같은 기능이 비슷한 경우에 도움이되었습니다. docstring이 설명 하듯이 일반적인 경우에는 작동하지 않지만 노드가 고유하다면 도움이됩니다.

def get_element_ancestry(root, element): 
'''Return a list of ancestor Elements for the given element. 

If both root and element are of type xml.etree.ElementTree.Element, and if 
the given root contains the given element as a descendent, then return a 
list of direct xml.etree.ElementTree.Element ancestors, starting with root 
and ending with element. Otherwise, return an empty list. 

The xml.etree.ElementTree module offers no function to return the parent of 
a given Element, presumably because an Element may be in more than one tree, 
or even multiple times within a given tree, so its parent depends on the 
context. This function provides a solution in the specific cases where the 
caller either knows that the given element appears just once within the 
tree or is satisfied with the first branch to reference the given element. 
''' 
result = [] 
xet = xml.etree.ElementTree 
if not xet.iselement(root) or not xet.iselement(element): 
    return result 
xpath = './/' + element.tag \ 
    + ''.join(["[@%s='%s']" % a for a in element.items()]) 
parent = root 
while parent != None: 
    result.append(parent) 
    for child in parent.findall('*'): 
     if child == element: 
      result.append(element) 
      return result 
     if child.findall(xpath).count(element): 
      parent = child 
      break 
    else: 
     return [] 
return result 
+0

영업 시간이 3 년 이상입니다 ... 현재 답변이 현재 작동하는지, 이전 버전으로 이전 버전으로 사용했는지, 이전 버전으로 사용 중인지, 또는 관련 사실을 알고있는 anithing인지 명확히하는 것이 좋습니다. – gmo