2017-01-26 2 views
1

Мне нужно найти tag = ITEM, который соответствует 2 критериям, а затем получить родительский тег = NODE @ name на основе этой находки.ElementTree лучший способ поиска узлов (XPATH) с использованием AND и 'parent'

Два вопроса:

  1. Я не могу найти способ для XPath, чтобы сделать «и», например

    item = node.findall('./ITEM[@name="toppas_type" and @value="output file list"]') 
    
  2. Получение информации родительского узла без необходимости искать явно и сохранить его заранее, чтобы найти ПУНКТ, например, что-то вроде

    parent_name = item.parent.attrib['name'] 
    

Это код, у меня сейчас:

node_names = [] 
for node in tree.findall('NODE[@name="vertices"]/NODE'): 
    for item in node.findall('./ITEM[@name="toppas_type"]'): 
     if item.attrib['name'] == 'toppas_type' and item.attrib['value'] == 'output file list': 
      node_names.append(node.attrib['name']) 

... разобрать файл как это (сниппета только) ...

<?xml version="1.0" encoding="ISO-8859-1"?> 
<PARAMETERS version="1.6.2" xsi:noNamespaceSchemaLocation="http://open-ms.sourceforge.net/schemas/Param_1_6_2.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> 
    <NODE name="vertices" description=""> 
     <NODE name="23" description=""> 
      <ITEM name="recycle_output" value="false" type="string" description="" required="false" advanced="false" /> 
      <ITEM name="toppas_type" value="tool" type="string" description="" required="false" advanced="false" /> 
      <ITEM name="tool_name" value="FileConverter" type="string" description="" required="false" advanced="false" /> 
      <ITEM name="tool_type" value="" type="string" description="" required="false" advanced="false" /> 
      <ITEM name="x_pos" value="-620" type="double" description="" required="false" advanced="false" /> 
      <ITEM name="y_pos" value="-1380" type="double" description="" required="false" advanced="false" /> 
     </NODE> 

     <NODE name="24" description=""> 
      <ITEM name="recycle_output" value="false" type="string" description="" required="false" advanced="false" /> 
      <ITEM name="toppas_type" value="output file list" type="string" description="" required="false" advanced="false" /> 
      <ITEM name="x_pos" value="-440" type="double" description="" required="false" advanced="false" /> 
      <ITEM name="y_pos" value="-1480" type="double" description="" required="false" advanced="false" /> 
      <ITEM name="output_folder_name" value="" type="string" description="" required="false" advanced="false" /> 
     </NODE> 

     <NODE name="33" description=""> 
      <ITEM name="recycle_output" value="false" type="string" description="" required="false" advanced="false" /> 
      <ITEM name="toppas_type" value="merger" type="string" description="" required="false" advanced="false" /> 
      <ITEM name="x_pos" value="-620" type="double" description="" required="false" advanced="false" /> 
      <ITEM name="y_pos" value="-1540" type="double" description="" required="false" advanced="false" /> 
      <ITEM name="round_based" value="false" type="string" description="" required="false" advanced="false" /> 
     </NODE> 
    <!--(snip)--> 
    </NODE> 
</PARAMETERS> 

UPDATE:
@Mathias Müller

Отличное предложение - к сожалению, когда я пытаюсь загрузить файл XML, я получаю сообщение об ошибке. Я не знаком с lxml ... поэтому я не уверен, правильно ли я использую его.

from lxml import etree 
root = etree.DTD("/Users/mikes/Documents/Eclipseworkspace/Bioproximity/Assay-Workflows-Mikes/protein_lfq/protein_lfq-1.1.2.toppas") 
Traceback (most recent call last): 
File "<stdin>", line 1, in <module> 
File "src/lxml/dtd.pxi", line 294, in lxml.etree.DTD.__init__ (src/lxml/lxml.etree.c:187024) 
lxml.etree.DTDParseError: Content error in the external subset, line 2, column 1 

К сожалению, ElementTree не признать, что в его XPath tree.find (XPATH) или tree.findall (XPATH)

+0

Пожалуйста, ясно показывают, что вы хотел бы, чтобы результат был таким, как только входной документ, который вы сюда включили. Благодарю. –

ответ

1

Возможно, вам не нужны вложенные циклы вообще, одно выражение XPath будет достаточно , Я не совсем уверен, что вы хотели бы, чтобы конечный результат будет, но вот пример с lxml:

>>> import lxml.etree 
>>> s = '''<NODE name="vertices" description=""> 
... 
...  <NODE name="23" description=""> 
...  <ITEM name="recycle_output" value="false" type="string" description="" required="false" advanced="false" /> 
...  <ITEM name="toppas_type" value="tool" type="string" description="" required="false" advanced="false" /> 
...  <ITEM name="tool_name" value="FileConverter" type="string" description="" required="false" advanced="false" /> 
...  <ITEM name="tool_type" value="" type="string" description="" required="false" advanced="false" /> 
...  <ITEM name="x_pos" value="-620" type="double" description="" required="false" advanced="false" /> 
...  <ITEM name="y_pos" value="-1380" type="double" description="" required="false" advanced="false" /> 
...  </NODE> 
... 
...  <NODE name="24" description=""> 
...  <ITEM name="recycle_output" value="false" type="string" description="" required="false" advanced="false" /> 
...  <ITEM name="toppas_type" value="output file list" type="string" description="" required="false" advanced="false" /> 
...  <ITEM name="x_pos" value="-440" type="double" description="" required="false" advanced="false" /> 
...  <ITEM name="y_pos" value="-1480" type="double" description="" required="false" advanced="false" /> 
...  <ITEM name="output_folder_name" value="" type="string" description="" required="false" advanced="false" /> 
...  </NODE> 
... 
...  <NODE name="33" description=""> 
...  <ITEM name="recycle_output" value="false" type="string" description="" required="false" advanced="false" /> 
...  <ITEM name="toppas_type" value="merger" type="string" description="" required="false" advanced="false" /> 
...  <ITEM name="x_pos" value="-620" type="double" description="" required="false" advanced="false" /> 
...  <ITEM name="y_pos" value="-1540" type="double" description="" required="false" advanced="false" /> 
...  <ITEM name="round_based" value="false" type="string" description="" required="false" advanced="false" /> 
...  </NODE> 
... <!--(snip)--> 
... </NODE>''' 
>>> root = lxml.etree.fromstring(s) 
>>> root.xpath('/NODE[@name="vertices"]/NODE/ITEM[@name = "toppas_type" and @value = "output file list"]') 
[<Element ITEM at 0x102b5f788>] 

И если вы на самом деле нужно имя родительского элемента, вы можете перейти к родительскому узлу с ..:

>>> root.xpath('/NODE[@name="vertices"]/NODE/ITEM[@name = "toppas_type" and @value = "output file list"]/../@name') 
['24'] 

синтаксический документ XML из файла

функция etree.DTD неправильный выбор, если вы хотите, чтобы разобрать XML документ фр om файл. DTD не является документом XML. Вот как вы можете сделать это с lxml:

>>> import lxml.etree 
>>> root = lxml.etree.parse("example.xml") 
>>> root 
<lxml.etree._ElementTree object at 0x106593b00> 

Второе обновление

Если внешний элемент PARAMETERS, вам нужно искать так:

>>> root.xpath('/PARAMETERS/NODE[@name="vertices"]/NODE/ITEM[@name = "toppas_type" and @value = "output file list"]') 
[<Element ITEM at 0x106593e18>] 
+0

Отличное предложение - к сожалению, когда я пытаюсь загрузить файл XML, я получаю сообщение об ошибке. Я не familiar с lxml ... поэтому я не уверен, что я подал в суд на это.
root = etree.DTD ("/ Users/mikes/Documents/Eclipseworkspace/Bioproximity/Assay-Workflows-Mikes/protein_lfq/protein_lfq-1.1.2.toppas ")
Traceback (самый последний звонок последний):
Файл" », строка 1, в
Файл "SRC/LXML/dtd.pxi", строка 294, в lxml.etree.DTD .__ init__ (src/lxml/lxml.etree.c: 187024)
lxml.etree.DTDParseError: ошибка содержимого во внешнем подмножестве, строка 2, столбец 1 – RightmireM

+0

@BurningKrome Вопрос состоял в том, что вы разбираете XML-документ, но ' etree.DTD' предполагает, что вы работаете с _DTD_ (вы не упомянули об этом до сих пор). Возможно, вам нужно обновить вопрос тем, что вы пытаетесь сделать _actually_ или открыть другой вопрос? –

+0

Извините. Это файл XML Честно говоря, Googling, как открыть файл, придумал DTD (и не намного больше): D – RightmireM