2011-03-21 2 views
1

У меня есть большой документ XML, который выглядит следующим образом:питон прибудете XML запрос родитель

<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> 

Моя миссия состоит в том, чтобы получить значение родительского узла: 1764466544 (значение имени в 2 узла) посредством производства поиск, чтобы найти, если подэлемент узла Val name = "number" содержит 265456

Я делал кучу чтения на XPath и ElementTree, но я все еще не уверен, с чего начать на самом деле запрашивать это. Ищите примеры ... В результате я не могу найти ссылку на родительский узел.

Еще новичок в python .. любые предложения будут оценены.

Благодаря

ответ

3

Это XPath:

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

Выходы:

1764466544 
+0

@itwb - Я никогда не пытался XPath на Python, так что часть зависит от вас, но 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 с ведущим '/': 'raise SyntaxError (" не может использовать абсолютный путь для элемента ")'. Может быть, попробуйте относительное выражение? Этот 'Node/Node [Val [@ name = 'number']/f = '265456']/@ name' или этот' // Node/Node [Val [@ name = 'number']/f = '265456' ]/@ name' –

-2

Обычно

node.parentNode 

возвратит potiner к родительскому узлу (при использовании DOM парсер).

Для XPath см

http://www.tizag.com/xmlTutorial/xpathparent.php

+0

Это не работает с ElementTree, такого атрибута в любой версии библиотеки нет. – Stabledog

3

К сожалению, при использовании API ElementTree, каждый Element объект не имеет никакого отношения назад его родителям, поэтому вы c аннота поднимается по дереву из известной точки. Вместо этого вы должны найти возможные родительские объекты и отфильтровать те, которые вы хотите.

Это обычно делается с выражениями XPath. Однако ElementTree поддерживает только подмножество XPath (see the docs), наиболее полезные части которого были добавлены только в ElementTree 1.3, который поставляется только с Python 2.7+ или 3.2+.

И даже XPath XP ElementTree он не может работать с вашим файлом, как есть - нет способа выбрать на основе текста узла, только его атрибуты (или значения атрибутов).

Мои эксперименты нашли только два способа, которыми вы можете продолжить с помощью ElementTree. Если вы используете Python 2.7+ (или можете загружать и устанавливать более новую версию ElementTree для работы со старыми версиями Python), и вы можете изменить формат XML-файла, чтобы поместить числа в качестве атрибутов, например

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

то следующий код Python будет вытаскивать узлы, представляющие интерес:

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

для старших питонов, или если вы не можете изменить формат XML, вы должны отфильтровать недопустимые узлы вручную ,Следующие работал для меня:

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 (так как это то, что вы упомянутый используя). Возможно, вам лучше использовать стороннюю библиотеку, а не использовать встроенные; см. the Python wiki entry on XML для получения списка опций. lxml - это привязки Python для широко используемой библиотеки libxml2, и я бы предложил сначала посмотреть. Он поддерживает XPath, поэтому вы должны иметь возможность использовать запросы из других ответов.

+0

Действительно раздражает, что Python добавил некоторую поддержку XPath, но я не могу использовать синтаксис «..», чтобы перейти от текущего узла. Он должен быть указан в Python [documentation] (https://docs.python.org/2.7/library/xml.etree.elementtree.html). Фактически в [документации] (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

OP более 3-х лет ... Рекомендуется прояснить, действительно ли ваш ответ работает, с текущей версией, использовать для работы до, со старыми версиями или анифингами, которые вы считаете актуальными, зная об этом. – gmo

Смежные вопросы