简体   繁体   中英

insert a new line and some text after matching some text c#

i have a txt file that contain

<?xml version="1.0" blablabla ..etc>
  <uses-permission ~~~~~~ ..etc>
  <application ~~~some of words i dont know it and changes from file to another file~~~ >
  </application>
</manifest>

i need to add "Hello World" in new line at a specific position and the final file will be look like this

<?xml version="1.0" blablabla ..etc>
  <uses-permission ~~~~~~ ..etc>
Hello World
  <application ~~~some of words i dont know it and changes from file to another file~~~ >
Hello World
  </application>
</manifest>

pls, how can i do this in c#? and i dont know some words in the line that i will add "Hello World" After it so i need to detect the line first like "<application " in line 195 then add a new line after 195 it will be 196 then add the words "Hello World"

  • You want to manipulate an Android app manifest XML file.
  • Use the right tool for the right job .
    • Do not process XML documents as text :
    • This means you should use a XML-procesing library instead. Fortunately .NET has at least 2 of them:
      • System.Xml - this is the older XML library from .NET Framework 1.x days (2000-2002). It is modelled on an early standard for the W3C DOM and is very hard to use.
      • System.Xml.Linq (aka " Linq to XML" ) - this is a modern (relatively speaking) library that came out in .NET Framework 3.5 (at the same time as Linq and all manner of nice things that we still enjoy today). The API design is very different, but also far more succinct and expressive compared to System.Xml . I note that it is designed primarily for querying XML instead of mutating XML, but for our purposes it's fine.

While (generally speaking), the order of elements in Android manifest files does not matter, there are 2 documented exceptions where order does matter , and unfortunately for us the 2nd exception applies to us :

  1. An <activity-alias> element must follow the <activity> for which it is an alias.
  2. The <application> element must be the last element inside the <manifest> element.

So the bird's eye view is:

  1. Load the Android app manifest XML file into an XDocument object.
  2. To add a new <uses-permission> element or a new <permission> element , you need to add as an immediate child of the root <manifest> element, but located before the <application> element.
  3. To add a new <service> element you append it to <application> as a new immediate-child element.

Like so:

using System.Linq;
using System.Xml.Linq;

public static class Program
{
    const String FILE_NAME = "MyManifest.xml";

    public static async Task<Int32> Main( String[] args )
    {
        if( !File.Exists( FILE_NAME ) )
        {
            Console.WriteLine( "Couldn't find \"" + FILE_NAME + "\"." );
            return 1;
        }

        String manifestXmlText = await File.ReadAllTextAsync( FILE_NAME  );

        XDocument manifestXml = XDocument.Parse( manifestXmlText );

        XElement applicationEl = manifestXml.Descendants("application"); // Get the <application> element.

        XNamespace? androidNS = manifestEl.GetNamespaceOfPrefix(prefix: "android"); // "http://schemas.android.com/apk/res/android"
        if( androidNS is null ) throw new InvalidOperationException( "Couldn't find xmlns:android" );

        {
            // <uses-permission>'s attributes use XML namespaces, so this complicates things:
            // https://stackoverflow.com/questions/4985974/xelement-namespaces-how-to
            // https://docs.microsoft.com/en-us/dotnet/standard/linq/namespaces-overview
            // https://stackoverflow.com/questions/2874422/how-to-set-the-default-xml-namespace-for-an-xdocument
            // https://stackoverflow.com/questions/1338517/how-can-i-write-xml-with-a-namespace-and-prefix-with-xelement

            XElement newUsesPermissionEl = new XElement( "uses-permission",
                new XAttribute( androidNS + "name"         , "bar"), 
                new XAttribute( androidNS + "maxSdkVersion", "123")
            );

            appEl.AddBeforeSelf( newUsesPermissionEl ); // Add the new <uses-permission> element as a preceding sibling of <application>.
        }

        {
            // <service>:

            XElement newServiceEl = new XElement( "service",
                new XAttribute( androidNS + "description", "Some day, some day, Some day, Dominion; Some day, some day, Some say prayers; I say mine"), 
                new XAttribute( androidNS + "name"       , "Dominion service"),
                new XAttribute( androidNS + "label"      , "Andrew Eldritch fanclub <3"),
            );

            appEl.Add( newServiceEl ); // Add the new <service> element as an immediately child of <application>.
        }

        // Then save the XML document:
        using( FileStream fs = File.OpenWrite( FILE_NAME ) )
        {
            await manifestXml.SaveAsync( fs );
        }

        return 0;
    }
}

So given the official example Manifest XML as input (in MyManifest.xml )...:

<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="com.example.myapp">
  <!-- Beware that these values are overridden by the build.gradle file -->
  <uses-sdk android:minSdkVersion="15" android:targetSdkVersion="26" />
  <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:roundIcon="@mipmap/ic_launcher_round" android:label="@string/app_name" android:supportsRtl="true" android:theme="@style/AppTheme">
    <!-- This name is resolved to com.example.myapp.MainActivity
             based upon the package attribute -->
    <activity android:name=".MainActivity">
      <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
      </intent-filter>
    </activity>
    <activity android:name=".DisplayMessageActivity" android:parentActivityName=".MainActivity" />
  </application>
</manifest>

...I get this output:

<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="com.example.myapp">
  <!-- Beware that these values are overridden by the build.gradle file -->
  <uses-sdk android:minSdkVersion="15" android:targetSdkVersion="26" />
  <uses-permission android:name="bar" android:maxSdkVersion="123" />
  <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:roundIcon="@mipmap/ic_launcher_round" android:label="@string/app_name" android:supportsRtl="true" android:theme="@style/AppTheme">
    <!-- This name is resolved to com.example.myapp.MainActivity
             based upon the package attribute -->
    <activity android:name=".MainActivity">
      <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
      </intent-filter>
    </activity>
    <activity android:name=".DisplayMessageActivity" android:parentActivityName=".MainActivity" />
    <service android:description="Some day, some day, Some day, Dominion; Some day, some day, Some say prayers; I say mine" android:name="Dominion service" android:label="Andrew Eldritch fanclub &lt;3" />
  </application>
</manifest>

As you can see, the <service> and <uses-permission> elements have been inserted in their correct places.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM