2016-08-17 64 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]: