使用lxml获取特定的元素属性



我有以下xml文件,我需要到达一个特定的块并更改2个属性值。

xml文件- https://alvinalexander.com/java/jwarehouse/activemq/assembly/src/release/conf/jetty.xml.shtml

我在本地有。

我需要编辑的块:

<bean class="org.eclipse.jetty.webapp.WebAppContext">
<property name="contextPath" value="/admin" />
<property name="resourceBase" value="${activemq.home}/webapps/admin" />
<property name="logUrlOnStart" value="true" />
</bean>

我需要改变属性<property name="contextPath" value="/admin" />的值

<property name="resourceBase" value="${activemq.home}/webapps/admin" />

<property name="contextPath" value="/hawtio" />

<property name="resourceBase" value="${activemq.home}/webapps/hawtio" />

我也需要不使用索引,我需要使用xpath。

这意味着,我希望使用xpath到达特定的元素并更改其属性不使用(例如)tree[i]

我的python代码(或者至少我期望做的)

import lxml
from lxml import etree
#Initialise xml file , xml file has namespaces
tree = etree.parse("jetty.xml")
myroot = tree.getroot()
#XML File has atleast 5 childs to each element
#From here i expect to edit attributes without using
#Manual indexing , for example
#prop = myroot.find('property[@name="contextPath"]')
#prop.attrib['value'] = '/hawtio'
#prop = myroot.find(('./property[@name="resourceBase"]'))
#prop.attrib['value'] = "${activemq.home}/webapps/hawtio"
#etree.write("jetty.xml", pretty_print=True)

再次,我正在解析一个具有名称空间和许多子元素的文件,运行find()返回None并运行findall()返回一个空列表,使用名称空间运行这些选项也返回空列表 None

进一步解释-打开xml文件,找到特定的元素并编辑它们的属性NO MATTER它们的索引(例如myroot[0][2]),并将更改写回文件。

欢呼,

试试下面的代码(不使用外部库)

import xml.etree.ElementTree as ET

xml = '''<bean class="org.eclipse.jetty.webapp.WebAppContext">
<property name="contextPath" value="/admin" />
<property name="resourceBase" value="${activemq.home}/webapps/admin" />
<property name="logUrlOnStart" value="true" />
</bean>'''

root = ET.fromstring(xml)
prop = root.find('./property[@name="contextPath"]')
prop.attrib['value'] = 'new_value_goes_here'
ET.dump(root)

输出
<bean class="org.eclipse.jetty.webapp.WebAppContext">
<property name="contextPath" value="new_value_goes_here" />
<property name="resourceBase" value="${activemq.home}/webapps/admin" />
<property name="logUrlOnStart" value="true" />
</bean>

使用balderman的答案,我能够找到一个解决方案。

import lxml
from lxml import etree 
#Initialise xml file
tree = etree.parse("jetty.xml")
myroot = tree.getroot()
test = myroot.find('.//*[@name="contextPath"]')
print(test)

收益率:

Element {http://www.springframework.org/schema/beans}property at

的属性:

print(test.attrib)
{'name': 'contextPath', 'value': '/admin'}

改变价值观:

prop = myroot.find('.//*[@name="contextPath"]')
prop.attrib['value'] = '/hawtio'
prop = myroot.find(('.//*[@name="resourceBase"]'))
prop.attrib['value'] = "${activemq.home}/webapps/hawtio"
etree.write("jetty.xml", pretty_print=True)

我在find()[@name="contextPath"]上使用.//*选项因为我知道元素contextPath只出现了一次因此,如果将来将另一个contextPath元素添加到文件中,则我的解决方案不是很好,如果您找到比我更好的解决方案,请发布它。

编辑:

刚刚注意到文件被更新了,这里是一个更新

prop = myroot.findall('.//*[@name="contextPath"]')
for i in prop:
if '/admin' in i.attrib.itervalues():
prop.attrib['value'] = '/hawtio'

prop = myroot.findall(('.//*[@name="resourceBase"]'))
for i in prop:
if '${activemq.home}/webapps/admin' in i.attrib.itervalues():
prop.attrib['value'] = '${activemq.home}/webapps/hawtio'

由于属性是作为键值返回的,我们可以使用内置的dictitervalues()函数来针对特定的键。

最新更新