2013-03-26 52 views
8

我是一名编程新手,很少使用Python,因此请耐心等待,因为我试图解释我是什么试图做:)Python版本2.7:XML ElementTree:如何遍历子元素的某些元素以便找到匹配

我有下面的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()并从那里向后工作。因为它代表这是我的伪代码:

  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:

在SVK下面我建议尝试以下内容:

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 

但我得到的唯一输出是: 患者 患者 并且没有较低标记。有任何想法吗?

+0

你似乎不有一个顶层标签,例如''您是否编辑过该文件,或者这是您的文档? – MattH 2013-03-26 17:05:44

+0

对不起,只是现在就把它加进去了。谢谢! – 2013-03-26 17:19:04

+1

我会在这里使用'lxml'(与API兼容的库)并使用xpath表达式。使用正确的XPath表达式选择正确的访问非常简单。 – 2013-03-26 17:34:51

回答

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) 
+2

这个工程!许多很多很多谢谢,我不能相信这是很容易,踢我自己!顺便说一句,你是一个天才:) – 2013-03-26 17:40:52

5

您可以直接下一个元素“元素”像这样在所有的“访问”标签迭代:

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

你可以找到一个特定的标签匹配与元素的第一直接子:

element.find("visits") 

看起来您首先必须找到“访问”的父级“访问”元素,然后遍历其“访问”子级。把这些在一起你有这样的事情:

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.etree文档中的部分一般看。ElementTree的:http://docs.python.org/2/library/xml.etree.elementtree.html#finding-interesting-elements

+0

非常感谢,我试过你的答案,但无济于事,看到编辑1. – 2013-03-26 17:22:56

+0

对不起,答案有点乱。我相信你错过的是child.find(“blah”)本身不会做任何事 - 它会返回找到的节点。您需要使用返回值来继续搜索。 – svk 2013-03-26 17:40:32

0

你可以使用一个CssSelector让你从病人的元素想要的节点:

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

你可以做同样得到patientCode标签和SWOL28标签 那么你就可以访问和modifiy元素的使用element.text

+0

我的python版本没有lxml,我查看了它的安装,它有点超出我的深度!虽然谢谢! – 2013-03-26 17:24:58

+0

在命令行中很简单:'pip install lxml' – niroyb 2013-03-26 17:32:50

0

如果使用lxml.etree,您可以使用xpath找到你需要更新的元素。

E.g.

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>