如何用Python ElementTree提取符合条件的XML用户节点name属性
问题描述
需要从给定XML文件中提取<user>节点的name属性值,筛选条件为该<user>节点下属的<job>节点需同时满足kind="al"和run="jps"。使用ElementTree尝试提取时,因getparent()方法不支持而失败。
目标XML内容
<maruti> <usrDirectory>/usr</usrDirectory> <shareDirectory>/share</shareDirectory> <jobLogDirectory>/logs</jobLogDirectory> <clients> <client>nexa-asia</client> </clients> <imax> <uri>imaxs://imax-asia.fb.bda.com:123</uri> <rootDn>o=lbr</rootDn> <pend>ou=nexa-asia,ou=clients,o=lbr</pend> <password>password</password> </imax> <enabling-aling-tags> <tag>alingDisabled</tag> </enabling-aling-tags> <maxh>999</maxh> <defaults> <default type="slone"> <user>pot</user> <exec>/usr/local/smarts/utils/runals.sh</exec> <env> <var name="ALARM">/taj/63123.lbr/ALARM</var> <var name="TODAY">/taj/63123.lbr/TODAY</var> <var name="jps_HOME">/usr/juju</var> </env> </default> <default type="slanamb"> <user>pot</user> <exec>/usr/local/smarts/utils/runals.sh</exec> <env> <var name="ALARM">/taj/63123.lbr/ALARM</var> <var name="TODAY">/taj/63123.lbr/TODAY</var> <var name="jps_HOME">/usr/juju</var> </env> </default> <default type="slaljps"> <user>pot</user> <exec>/use-ALARM/runmrts.sh</exec> <env> <var name="jps_HOME">/usr/juju</var> </env> </default> <default type="slanjps"> <user>pot</user> <exec>/use-ALARM/runmrts.sh</exec> <env> <var name="jps_HOME">/usr/juju</var> </env> </default> <default type="cmj"> <user>pot</user> <exec>/use-ALARM/runmrts.sh</exec> <env> <var name="jps_HOME">/usr/juju</var> </env> </default> <default type="cbj"> <user>pot</user> <exec>/use-ALARM/runmrts.sh</exec> <env> <var name="jps_HOME">/usr/juju</var> </env> </default> <default type="slm"> <user>favactor</user> <exec>/usr/local/actdrive/actdrive</exec> <args> <arg name="config">/usr01/lbr/conf/lbr-naming.properties</arg> </args> </default> <default type="tata"> <user>pot</user> <exec>/use-ALARM/tataals.sh</exec> <env> <var name="jps_HOME">/usr/juju</var> </env> </default> </defaults> <groups> <user name="nexa_sit" annvday="20221003" make="one"> <jobs> <job kind="al" run="jps"> <args> <arg name="level">5000</arg> </args> </job> <job kind="vm" run="jps"> <args> <arg name="level">5000</arg> </args> </job> </jobs> </user> <user name="nexa_tsx" annvday="20230714" make="two"> <jobs> <job kind="al" run="jps"> <args> <arg name="level">5000</arg> </args> </job> <job kind="vm" run="jps"> <args> <arg name="level">5000</arg> </args> </job> </jobs> </user> <user name="nexatwo_bvk" annvday="20221003" make="one"> <jobs> <job kind="al" run="jps"> <args> <arg name="level">5000</arg> </args> </job> <job kind="vm" run="jps"> <args> <arg name="level">5000</arg> </args> </job> </jobs> </user> <user name="nexaone_bvk" annvday="20221003" make="one"> <jobs> <job kind="al" run="ips"> <args> <arg name="level">5000</arg> </args> </job> <job kind="vm" run="ips"> <args> <arg name="level">5000</arg> </args> </job> </jobs> </user> </groups> </maruti>
尝试的代码
import xml.etree.ElementTree as ET tree = ET.parse('text.xml') root = tree.getroot() for sub in root.findall(".//user/jobs/job"): if (sub.attrib["run"] == 'java' and sub.attrib["kind"] == 'al'): print sub.getparent()
预期输出
nexa_sit nexa_tsx nexatwo_bvk
解决方案
方法1:通过XPath向上遍历父节点
利用XPath的..语法获取父节点,先定位符合条件的<job>,再逐层向上找到<user>节点:
import xml.etree.ElementTree as ET tree = ET.parse('text.xml') root = tree.getroot() # 直接筛选出满足kind="al"且run="jps"的job节点 for job in root.findall(".//job[@kind='al'][@run='jps']"): # 先找到jobs节点,再找到其父节点user user_node = job.find('../..') print(user_node.attrib['name'])
方法2:遍历user节点并检查子节点
先获取所有<user>节点,再逐个检查其下是否存在符合条件的<job>:
import xml.etree.ElementTree as ET tree = ET.parse('text.xml') root = tree.getroot() for user in root.findall(".//user"): # 检查当前user下是否有满足条件的job matched_jobs = user.findall("./jobs/job[@kind='al'][@run='jps']") if matched_jobs: print(user.attrib['name'])
原代码错误分析
- 条件匹配错误:原代码中判断
run="java",但需求是run="jps",导致无法筛选到目标节点。 - 方法过时:
getparent()方法在新版ElementTree中已被移除,推荐使用XPath的..语法来获取父节点,避免依赖内部属性。
内容的提问来源于stack exchange,提问作者upkar
相关产品推荐
相关产品推荐

