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:
- для каждой строки в текстовом файле:
- поместите Visit_Date Patient_Code New_SWOL28 в переменные
- для каждого элемента пациента:
- Если patientCode = Patient_Code
- для каждого элемента посещения:
- Если VisitDate = Visit_Date
- если элемент SWOL28 существует для этого посещения
- обновить 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 ответа:
Это непроверенное им должно быть довольно близко к тому, что вы хотите.
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>