【问题标题】:Python version 2.7: XML ElementTree: How to iterate through certain elements of a child element in order to find a matchPython 2.7 版:XML ElementTree:如何遍历子元素的某些元素以找到匹配项
【发布时间】:2013-03-26 17:01:34
【问题描述】:

我是一个编程新手,很少使用 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”值,如果它们与我存储在文本文件中的患者代码和访问日期相匹配。据我了解, 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

但我得到的唯一输出是: 病人 病人 并且没有较低的标签。有什么想法吗?

【问题讨论】:

  • 您似乎没有顶级标签,例如&lt;Patients&gt; 您是否将其编辑掉了,还是您的文档原样?
  • 抱歉,刚刚添加了。谢谢!
  • 我会在这里使用lxml(API 兼容库)并使用 xpath 表达式。使用正确的 XPath 表达式选择正确的访问非常容易。

标签: python xml elementtree


【解决方案1】:

您可以像这样直接在元素“元素”下遍历所有“访问”标签:

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

您可以找到与某个标签匹配的元素的第一个直接子元素:

element.find( "visits" )

看起来您首先必须找到“visit”元素,它是“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.etree.ElementTree 文档中的“寻找有趣元素”部分:http://docs.python.org/2/library/xml.etree.elementtree.html#finding-interesting-elements

【讨论】:

  • 非常感谢,我尝试了您的回答,但无济于事,请参阅编辑 1。
  • 对不起,答案有点乱。我相信您错过的事情是 child.find("blah") 自己不会做任何事情——它会 return 它找到的节点。您需要使用返回值来继续搜索。
  • elem.iter('visit') 是否遍历具有“访问”标签的“elem”(第一级或内部级别)标签中的所有元素?还是只针对一级孩子?
【解决方案2】:

这是未经测试的,它应该与您想要的相当接近。

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)

【讨论】:

  • 行得通!非常感谢,我不敢相信这很容易,踢自己!!!顺便说一句,你是个天才:)
【解决方案3】:

您可以使用 CssSelector 从 Patient 元素中获取您想要的节点:

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

你可以做同样的事情来获取 PatientCode 标签和 SWOL28 标签 然后你可以使用element.text访问和修改元素的文本

【讨论】:

  • 我的python版本没有lxml,我考虑安装它,但它有点超出我的深度!不过谢谢!
【解决方案4】:

如果您使用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>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-04-20
    • 2015-05-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多