如何使用Python etree lxml xpath设置/替换xml中的值?

如何使用Python etree lxml xpath设置/替换xml中的值?,xml,python-2.7,xpath,lxml,Xml,Python 2.7,Xpath,Lxml,我想用Python2.7和etree/lxml/xpath解析一个AndroidManifest.xml,以查找属性名,并获取和设置它们的值 AndroidManifest.xml: <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.android.wearable

我想用Python2.7和etree/lxml/xpath解析一个AndroidManifest.xml,以查找属性名,并获取和设置它们的值

AndroidManifest.xml:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.android.wearable.timer" >
<uses-sdk android:minSdkVersion="20"
          android:targetSdkVersion="22" />
<application
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:theme="@android:style/Theme.DeviceDefault.Light"
        android:allowBackup="true">
</application>
</manifest>
这就是我到目前为止所做的:

from lxml import etree
NS = {'android' : 'http://schemas.android.com/apk/res/android'}
tree = etree.parse('AndroidManifest.xml')
# get values
print tree.xpath("///@android:allowBackup", namespaces=NS)[0]
print tree.xpath("///@android:minSdkVersion", namespaces=NS)[0]
# set values ?
# write changes back to file ?
print etree.tostring(tree, encoding='utf-8', pretty_print=True)
这将打印true、20,然后打印整个未更改的xml文档

  • 如何将allowBackup和minSdkVersion的值分别设置为false和19?
奖金:

  • 如果android:allowBackup或android:minSdkVersion尚未出现,如何添加它们
  • 如何将更改写回文件
这给了你:

<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.android.wearable.timer">
<uses-sdk android:minSdkVersion="17" android:targetSdkVersion="22"/>
<application android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:theme="@android:style/Theme.DeviceDefault.Light" android:allowBackup="false">
</application>
</manifest>
new.xml:

<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.android.wearable.timer">
<uses-sdk android:minSdkVersion="17" android:targetSdkVersion="22"/>
<application android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:theme="@android:style/Theme.DeviceDefault.Light" android:allowBackup="false">
</application>
</manifest>

您现在知道如何编写更改,对于丢失的属性,它将按原样工作,如果值存在,我们将更新它,如果不存在,我们将创建它:

# no minSDk...
In [31]: !cat  test.xml<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.android.wearable.timer" >
<uses-sdk  android:targetSdkVersion="22" />
<application
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:theme="@android:style/Theme.DeviceDefault.Light"
        android:allowBackup="true">
</application>
</manifest>
In [32]: tree = et.parse("test.xml")

In [33]: root = tree.getroot()

In [34]: nsmap = root.nsmap

In [35]: android = nsmap["android"]

In [36]: tree.find("uses-sdk", nsmap).attrib[et.QName(android, "minSdkVersion")] = "17"

In [37]: tree.write("test.xml", encoding="utf-8")

# New attribute and value created.
In [38]: !cat  test.xml<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.android.wearable.timer">
<uses-sdk android:targetSdkVersion="22" android:minSdkVersion="17"/>
<application android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:theme="@android:style/Theme.DeviceDefault.Light" android:allowBackup="true">
</application>
</manifest>
In [39]: 
#没有minSDk。。。
在[31]:!cat test.xml
在[32]中:tree=et.parse(“test.xml”)
在[33]中:root=tree.getroot()
在[34]中:nsmap=root.nsmap
在[35]:android=nsmap[“android”]
在[36]中:tree.find(“使用sdk”,nsmap).attrib[et.QName(android,“minSdkVersion”)]=“17”
[37]:tree.write(“test.xml”,encoding=“utf-8”)
#创建新属性和值。
在[38]:!cat test.xml
在[39]中:
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.android.wearable.timer">
<uses-sdk android:minSdkVersion="17" android:targetSdkVersion="22"/>
<application android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:theme="@android:style/Theme.DeviceDefault.Light" android:allowBackup="false">
</application>
</manifest>
import lxml.etree as et
from StringIO import StringIO

tree = et.parse(StringIO(xml))
root = tree.getroot()
nsmap = root.nsmap
android = nsmap["android"]

tree.find("application", nsmap).attrib[et.QName(android, "allowBackup")] = "false"
tree.find("uses-sdk", nsmap).attrib[et.QName(android, "minSdkVersion")] = "17"

# write the updated html to "new.xml"
tree.write("new.xml", encoding="utf-8")
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.android.wearable.timer">
<uses-sdk android:minSdkVersion="17" android:targetSdkVersion="22"/>
<application android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:theme="@android:style/Theme.DeviceDefault.Light" android:allowBackup="false">
</application>
</manifest>
# no minSDk...
In [31]: !cat  test.xml<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.android.wearable.timer" >
<uses-sdk  android:targetSdkVersion="22" />
<application
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:theme="@android:style/Theme.DeviceDefault.Light"
        android:allowBackup="true">
</application>
</manifest>
In [32]: tree = et.parse("test.xml")

In [33]: root = tree.getroot()

In [34]: nsmap = root.nsmap

In [35]: android = nsmap["android"]

In [36]: tree.find("uses-sdk", nsmap).attrib[et.QName(android, "minSdkVersion")] = "17"

In [37]: tree.write("test.xml", encoding="utf-8")

# New attribute and value created.
In [38]: !cat  test.xml<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.android.wearable.timer">
<uses-sdk android:targetSdkVersion="22" android:minSdkVersion="17"/>
<application android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:theme="@android:style/Theme.DeviceDefault.Light" android:allowBackup="true">
</application>
</manifest>
In [39]: