Python elementree 可以获取大父属性值

Python elementree possible to get grand parent attribute value

提问人:upkar 提问时间:10/20/2023 更新时间:10/20/2023 访问量:34

问:

我有如下内容的xml文件。如果 XML 的属性作业与值“al”匹配,并且 run 将值匹配为“jps”,则要从 XML 中提取用户类别下的 name 值。尝试使用 elementree 提取值,但无法提取。不确定尝试的方法是否正确。

   <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>

但后来从错误中意识到不支持 getparent。不确定如何提取。

尝试过的代码

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_set
nexa_tfex
nexatwo_set
python 元素树

评论


答:

1赞 Larry 10/20/2023 #1

不幸的是,由于这是 Python 标准库中的包,因此您得到的界面相当有限,并且无法访问方便的导航功能,例如方法。xml.getparent()

一种选择是使用 代替 ,尽管它未包含在标准库中,但确实具有更高级的功能,包括以面向对象的方式导航节点树的方法。lxmlxml

但是,使用 ,您仍然拥有 XPath 本身的强大功能,或者至少是其中的有限子集,这确实允许您执行所需的操作。xml

从所选节点中,一旦验证给定节点具有所需的属性值,就可以返回到其祖父节点 (),方法是使用轴(有点像描述树节点关系的运算符)在层次结构中向上移动的次数。jobuserjob..

但是,由于您在验证孙子在 XPath 中执行导航,因此这意味着您还需要在 XPath 中执行验证。XPath 为此提供了谓词,表达式括在方括号中:[]

".//user/jobs/job[@run='jps'][@kind='al']"

上面的表达式表示“所有节点,其父节点是节点,其父节点是可以位于文档中任何位置的节点,所述节点具有以 value 等于 string 命名的属性,以及具有字符串值的属性。jobjobsuserjobrunjpskindal

从这一点开始,您可以使用父轴速记两次来返回到祖父轴:user

".//user/jobs/job[@run='jps'][@kind='al']/../.."

由于您在 XPath 查询中执行了所有必要的步骤,因此当您回到 Python 的世界时,您甚至不需要费心编写语句。if

编辑:请注意,与你的-testing方法相比,如果发现一个对象确实具有a或a属性,或者同时具有这两个属性,但具有与预期值不同的对象,XPath方法将简单地静默地忽略它们,而你的dict成员访问运算符将抛出一个错误(可能)。ifuser/jobs/jobrunkindKeyError