0

I need to read and replace a line in a .xml file. I tried almost everything that I could imagine based on Search and replace a line in a file in Python, also How to search and replace text in a file using Python?.

Then as a second step I thought that it would be possible to remove the line and print the new line on top based on Deleting a specific line in a file (python), also Deleting a line from a file in Python.

Unfortunately nothing worked correctly for me. Either the script writes all lines as the same output or the format is not correct after writing.

Then I start reading closser questions such as How to remove elements from XML using Python but again it was not I was trying to get as a final output.

Update: By accident I deleted one line and the whole xml code was not able to be seen.

Sample of *.xml file:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="gcm.play.android.samples.com.gcmquickstart"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="9"
        android:targetSdkVersion="23" />

    <!-- [START gcm_permission] -->
    <uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
    <uses-permission android:name="android.permission.WAKE_LOCK" />

    <!-- Required permission for App measurement to run. -->
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <!-- [END gcm_permission] -->
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="gcm.play.android.samples.com.gcmquickstart.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

I am trying to remove the line package="gcm.play.android.samples.com.gcmquickstart" with another line e.g. package="another.line"

The code that I am using:

def str_replace(file_input, keyword, str_new):
    for line in fileinput.input(file_input, inplace=True):
        line = line.rstrip('\r\n')
        print line.replace(keyword, str_new)
    fileinput.close()
    return

But it does not work correctly it just finds the string in the line and replaces just the string.

Sample of desired *.xml file:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="sample.different.line"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="9"
        android:targetSdkVersion="23" />

    <!-- [START gcm_permission] -->
    <uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
    <uses-permission android:name="android.permission.WAKE_LOCK" />

    <!-- Required permission for App measurement to run. -->
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <!-- [END gcm_permission] -->
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="gcm.play.android.samples.com.gcmquickstart.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

Update 2: Thanks to Nelson Guaman Leiva I have found a partial solution to my problem. I can manage to find and replace the string on the specific point of my file. My new problem is that I can not found a way to match after the pattern=*whatever text here*, I can only find and replace the whole word, I can not match and replace after the equal sign.

Sample of code based on new solution:

def find_and_replace(file_input, str_old, str_new):
    with open(file_input, 'r') as fr:
        xml_data = fr.read()
        xml_data = re.sub(r'{}=\"(.+?)\"'.format(str_old), str_new, xml_data)
    fr.closed
    return

Update 3: I forgot to include the writing part of the process in the file, the code is included under. I am not sure if this process is the fastest or more sufficient to read and write but it is one possible solution.

Sample of code:

def str_replace(self, file_input, str_old, str_new):
        with open(file_input, "r") as fr:
            xml_data = fr.read()
            xml_data = re.sub(r"{}=\"(.+?)\"".format(str_old), str_new, xml_data)
        fr.closed

        with open(file_input, "w") as fw:
            fw.write(xml_data)
        fw.closed

        self.replace_string = xml_data
        return self.replace_string

If I found a solution to my problem on how to match and replace everything after the package=*whatever here* because currently I replace the whole line, but at least it works as expected.

Thank you for your time and effort in advance.

Thanos
  • 1,618
  • 4
  • 28
  • 49
  • 1
    Your example doesn't have a _"package="_ line in it. Your before and after examples are identical. And then you say _" it just finds the string in the line and replaces just the string."_ but all you wanted to do was replace the string... what's the problem? – tdelaney Dec 10 '15 at 18:49
  • You are absolutely right, I do not know how or why the data that I post do not include the package file. I will update the data in a few hours as I do not have access on my pc. (Thank you for pointing out my error, apologies for wasting your time). – Thanos Dec 10 '15 at 21:23
  • @tdelaney Apologies again, the code is now fixed. I deleted one line and by accident the xml code was hidden. – Thanos Dec 10 '15 at 22:23

1 Answers1

1

you can use this for example.

import re
with open ("file.xml", "r") as myfile:
    data = myfile.read()

data = re.sub(r"android:name=\"android\.permission\.[A-Z\_]+", "xxxx", data)
print data

This will replace all the android.permission.TEXT to xxx.

you only have to replace that string.

nguaman
  • 925
  • 1
  • 9
  • 23
  • Thanks Nelson, that would be very useful on my next step, but for the moment I am trying to update my package line. Please updated code. Apologies for the confusion. – Thanos Dec 10 '15 at 22:24
  • 1
    I am thinking maybe a regex something among the lines `data = re.sub(r"package=\"any.possible.text.combination.here]+", "xxxx", data)`. Maybe something like that would work. But I do not know exactly how to do it. The problem is that I do not know either the combination of character or the number of dots. The only thing that I know is that starts with `package="anything.here"`. So it need to much any combination between the double quotation. Again, thank you for your time and effort. – Thanos Dec 11 '15 at 07:59