Python версии 2.7: XML ElementTree: как перебирать некоторые элементы дочернего элемента, чтобы найти соответствие


Я новичок в программировании и редко использую python, поэтому, пожалуйста, потерпите, пока я пытаюсь объяснить, что я пытаюсь сделать:)

У меня есть следующий XML:

<?xml version = "1.0" encoding = "utf-8"?>
<Patients>
    <Patient>
               <PatientCharacteristics>
                   <patientCode>3</patientCode>
               </PatientCharacteristics>
               <Visits>
                   <Visit>
                          <DAS>
                               <CRP>14</CRP>
                               <ESR/>
                               <Joints>
                                       <DAS_PROFILE>28/28</DAS_PROFILE>
                                       <SWOL28>20</SWOL28>
                                       <TEN28>20</TEN28>
                               </Joints>
                          </DAS>
                          <VisitDate>2010-02-17</VisitDate>
                   </Visit>
                   <Visit>
                          <DAS>
                               <CRP>10</CRP>
                               <ESR/>
                               <Joints>
                                       <DAS_PROFILE>28/28</DAS_PROFILE>
                                       <SWOL28>15</SWOL28>
                                       <TEN28>20</TEN28>
                               </Joints>
                          </DAS>
                          <VisitDate>2010-02-10</VisitDate>
                   </Visit>
               </Visits>
    </Patient>
    <Patient>
        <PatientCharacteristics>
                   <patientCode>3</patientCode>
        </PatientCharacteristics>
               <Visits>
                   <Visit>
                          <DAS>
                               <CRP>14</CRP>
                               <ESR/>
                               <Joints>
                                       <DAS_PROFILE>28/28</DAS_PROFILE>
                                       <SWOL28>34</SWOL28>
                                       <TEN28>0</TEN28>
                               </Joints>
                          </DAS>
                          <VisitDate>2010-08-17</VisitDate>
                   </Visit>
                   <Visit>
                          <DAS>
                               <CRP>10</CRP>
                               <ESR/>
                               <Joints>
                                       <DAS_PROFILE>28/28</DAS_PROFILE>
                                       <SWOL28></SWOL28>
                                       <TEN28>2</TEN28>
                               </Joints>
                          </DAS>
                          <VisitDate>2010-07-10</VisitDate>
                   </Visit>
                   <Visit>
                          <DAS>
                               <CRP>9</CRP>
                               <ESR/>
                               <Joints>
                                       <DAS_PROFILE>28/28</DAS_PROFILE>
                                       <SWOL28>56</SWOL28>
                                       <TEN28>6</TEN28>
                               </Joints>
                          </DAS>
                          <VisitDate>2009-07-10</VisitDate>
                   </Visit>
               </Visits>

    </Patient>
</Patients>

Все, что я хочу сделать здесь, это обновить некоторые значения 'SWOL28', если они соответствуют patientCode и VisitDate, которые я сохранил в текстовом файле. Как я понимаю, elementtree не включает родительскую ссылку, как если бы она была, я мог бы просто использовать findall() из корня и работать в обратном направлении оттуда. Как он стоит здесь-мой psuedocode:

  1. для каждой строки в текстовом файле:
  2. поместите Visit_Date Patient_Code New_SWOL28 в переменные
  3. для каждого элемента пациента:
  4. Если patientCode = Patient_Code
  5. для каждого элемента посещения:
  6. Если VisitDate = Visit_Date
  7. если элемент SWOL28 существует для этого посещения
  8. обновить SWOL28 до New_SWOL28

Но я застрял на шаге номер 5. Как мне получить список посещений, которые нужно повторить? Прошу прощения, если это так очень глупый вопрос, но я искал ответ повсюду, уверяю вас! Я сократил свой код до голого примера части, которую мне нужно исправить ниже:

import xml.etree.ElementTree as ET
tree = ET.parse('DB3.xml')
root = tree.getroot()
for child in root: # THIS GETS ME ALL THE PATIENT ATTRIBUTES
    print child.tag 
    for x in child/Visit: # THIS IS WHAT I CANNOT FIND THE CORRECT SYNTAX FOR
        # I WOULD THEN PERFORM STEPS 6, 7 AND 8 HERE
Я был бы глубоко признателен за любые идеи, которые кто-либо из вас может иметь по этому поводу. Я не программирую естественно, это точно!

Заранее спасибо, Сара

Править 1:

По совету СВК ниже я попробовал следующее:

import xml.etree.ElementTree as ET
tree = ET.parse('Untitled.xml')
root = tree.getroot()
for child in root:
    print child.tag 
    child.find( "visits" )
    for x in child.iter("visit"):
        print x.tag, x.text

Но единственный вывод, который я получаю, - это: Терпеливый Терпеливый и ни одной из нижних меток. Есть идеи?

4 9

4 ответа:

Это непроверенное им должно быть довольно близко к тому, что вы хотите.

for patient in root:
    patient_code =  patient.find('PatientCharacteristics').find('patientCode')
    if patient_code.text == code:
            for visit in patient.find('Visits'):
                    visit_date = visit.find('VisitDate')
                    if visit_date.text == date:
                        swol28 = visit.find('DAS').find('Joints').find('SWOL28')
                        if swol28.text:
                            visit.find('DAS').find('Joints').set('SWOL28', new_swol28)

Вы можете перебирать все теги "visit" непосредственно под элементом "element" следующим образом:

for x in element.iter("visit"):

Можно найти первый прямой потомок элемента, соответствующий определенному тегу:

element.find( "visits" )

Похоже, что сначала вам нужно будет найти элемент "visits", который является родителем элемента" visit", а затем перебрать его дочерние элементы" visit". Собирая их вместе, вы получите что-то вроде этого:

for patient_element in root:
    print patient_element.tag 
    visits_element = patient_element.find( "visits" )
    for visit_element in visits_element.iter("visit"):
        print visit_element.tag, visit_element.text
        # ... further processing of each visit element here

В общем взгляните на раздел "Поиск интересных элементов" в документация для xml.этри.ElementTree: http://docs.python.org/2/library/xml.etree.elementtree.html#finding-interesting-elements

Вы можете использовать CssSelector, чтобы получить нужные узлы из элемента Patient:

from lxml.cssselect import CSSSelector
visitSelector = CSSSelector('Visit')
visits =  visitSelector(child)

Вы можете сделать то же самое, чтобы получить тег patientCode и тег SWOL28 затем вы можете получить доступ и изменить текст элементов с помощью element.text

Если вы используете lxml.etree, вы можете использовать xpath для поиска элементов, которые необходимо обновить.

Например

doc.xpath('Patient[PatientCharacteristics/patientCode=$patient]/Visits/Visit[VisitDate=$visit]',patient="3",visit="2009-07-10")

Итак

from lxml import etree

doc = etree.parse("DB3.xml")

changes = [
  dict(patient='3',visit='2010-08-17',swol28="99"),
]

def update_doc(x,d):
  for row in d:
    for visit in x.xpath('Patient[PatientCharacteristics/patientCode=$patient]/Visits/Visit[VisitDate=$visit]',**row):
      for swol28 in visit.xpath('DAS/Joints/SWOL28'):
        swol28.text = row['swol28']

update_doc(doc,changes)

print etree.tostring(doc)

Должно дать вам что-то, что содержит:

<Patient>
  <PatientCharacteristics>
    <patientCode>3</patientCode>
  </PatientCharacteristics>
  <Visits>
    <Visit>
      <DAS>
      <CRP>14</CRP>
      <ESR/>
      <Joints>
        <DAS_PROFILE>28/28</DAS_PROFILE>
        <SWOL28>99</SWOL28>
        <TEN28>0</TEN28>
      </Joints>
    </DAS>
    <VisitDate>2010-08-17</VisitDate>
    </Visit>
  </Visits>
</Patient>