2016-08-17 268 views
1

我想用Python2.7和etree/lxml/xpath解析一个AndroidManifest.xml来查找属性名称并获取并设置它们的值。如何在Python中设置/替换xml中的值etree lxml xpath?

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

巴蜀我用这个xmlstarlet:

xmlstarlet ed --inplace -u '/manifest/application/@android:allowBackup' -v true AndroidManifest.xml 

这是我到目前为止有:

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) 

这将打印真,20然后整个不变的XML文件。

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

奖励:

  • 如何添加机器人:allowBackup或Android:如果的minSdkVersion他们不存在?
  • 如何将更改写回文件?

回答

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

要设置的值,查找节点然后访问那么它的ATTRIB字典使用QName,其中第一个参数是命名空间URI,第二个是属性名称设置它的属性的新值:

import lxml.etree as et 

tree = et.fromstring(xml) 
# holds namespace mappings 
nsmap = tree.nsmap 
# get prefix URI 
android = tree.nsmap["android"] 

# find app and set the attribute value. 
tree.find("application", nsmap).attrib[et.QName(android, "allowBackup")] = "false" 
tree.find("uses-sdk", nsmap).attrib[et.QName(android, "minSdkVersion")] = "17" 
print(et.tostring(tree, pretty_print=True)) 

它给你:

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

读取和并写入文件,逻辑仅仅是在同一最终你write传递文件名和任何其他ARGS:

​​

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