0

I have the following pom.xml file

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.qburst.app</groupId>
  <artifactId>main-app</artifactId>
  <packaging>jar</packaging>
  <version>1.0-SNAPSHOT</version>
  <name>main-app</name>
  <url>http://maven.apache.org</url>
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.12</version>
      <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>com.mycompany.app</groupId>
        <artifactId>my-app</artifactId>
        <version>1.1</version>
    </dependency>
 </dependencies>
<repositories>
 <repository>
    <id>maven</id>
    <url>http://nexus:8081/repository/maven-group/</url>
  </repository>
</repositories>
<distributionManagement>
  <snapshotRepository>
    <id>nexus</id>
    <url>http://nexus:8081/repository/maven-snapshots/</url>
  </snapshotRepository>
  <repository>
    <id>nexus</id>
    <url>http://nexus:8081/repository/maven-releases/</url>
  </repository>
</distributionManagement>
<build>
    <pluginManagement>
      <plugins>
        <plugin>
          <groupId>org.codehaus.mojo</groupId>
          <artifactId>versions-maven-plugin</artifactId>
          <version>2.5</version>
        </plugin>
      </plugins>
    </pluginManagement>
    <!-- To use the plugin goals in your POM or parent POM -->
    <plugins>
      <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>versions-maven-plugin</artifactId>
        <version>2.5</version>
      </plugin>
    </plugins>
</build>
</project>

I want to change a version of a particular dependency using sed command in terminal. However the following command doesnot seem to work:

sed -n -E 's/\(<dependency>[.\n\t ]*<groupId>com.mycompany.app<\/groupId>[.\S\w\n\t ]*<version>\)[0-9.]*\(<\/version>[.\n\t ]*<\/dependency>\)/\14.3\2/' pom.xml

I found out using online that the following regular expression is True However:

(<dependency>[.\n\t ]*<groupId>com.mycompany.app<\/groupId>[.\S\w\n\t ]*<version>)[0-9.]*(<\/version>[.\n\t ]*<\/dependency>)

However in sed it doesnot work. Someone please help

  • First of all welcome to Stack Overflow. We understand that your are excited about parsing XML with regex, but [just do not do it!](https://stackoverflow.com/a/1732454/8344060) Tools such as sed and AWK are extremely powerful for handling text files, but when it boils down to parsing complex-structured data — such as XML, HTML, JSON, ... — they are nothing more than a sledgehammer. Yes, you can get the job done, but sometimes at a tremendous cost. For handling such delicate files, you need a bit more finesse by using a more targetted set of tools. – kvantour Jul 20 '18 at 10:53
  • Not helpful. I could identify the element with the regular expression. However, in sed there was some problem. – ABEL KURUVILLA Jul 20 '18 at 10:58
  • @ABEL sed operates one line at a time, but you are trying to match multiple lines... and regex varies from tool to tool, the online tool you used probably is from a programming language like perl/python/javascript which is completely different than what is available for sed.. see https://unix.stackexchange.com/questions/119905/why-does-my-regular-expression-work-in-x-but-not-in-y – Sundeep Jul 20 '18 at 11:08
  • @ABELKURUVILLA you definetively *shold not* parse xml with regex, unless you also put in screws with hammer. – Gsk Jul 20 '18 at 11:11
  • while you might be able to use advanced features of sed to get it working for your current problem, it is better to use a tool like xmlstarlet which was built to work with xml files.. or use a programming language like python/perl + xml modules offered by them – Sundeep Jul 20 '18 at 11:11
  • @ABELKURUVILLA I understand that you can identify the node using regex. But this is in this case. Imagine now that your `pom.xml` is differently formatted (everything on a single line), will your regex still work? Or maybe the nodes are swapped around, or the attributes are all on different lines or whatever. There are almost an infinite amount of permutations possible to write identical interpretable XML files. Will the regex parse them all correct? Building a robust XML parser using regex is probably harder than hacking the Pentagon. – kvantour Jul 20 '18 at 12:13
  • @ABELKURUVILLA your response of `Not helpful` above was rude and incorrect since the comment you responded to is helpful. Responses like that will not encourage people to provide more of the help you're asking for - no-one wants to try to help you and then get smacked down with `Not helpful` and not so much as a thank you. – Ed Morton Jul 20 '18 at 13:55

1 Answers1

4

An excellent shell tool that can be used to do this job is . It is a bit a tough one to learn because it seems to go against everything that regex learned us as it makes use of XPath. But in the end, this is the way forward.

As you want to edit an XML file, the first thing you need to do is figure out the XPath you want to use. This is the most difficult task at hand here

Step 1: find the XPath you need

First you need to find the XPath that selects the right node. This can be done using the select option of . For this, you need to know

  1. your namespace. Your entire XML file is in the namespace: xmlns="http://maven.apache.org/POM/4.0.0", so every node needs to be referenced with this namespace.

  2. You are searching for a node named dependency who has a child groupId with a value com.mycompany.app. The XPath for this is:

    //N:dependency[N:groupId = "com.mycompany.app"]
    

    where N: is the namespace shorthand which we will define later.

  3. The value you want to change is the value of the child version, thus you have to add /N:version to the XPath expression.

So to see what you selected you can type:

$ xmlstarlet sel -N N="http://maven.apache.org/POM/4.0.0" \
                 -t -m '//N:dependency[N:groupId="com.mycompany.app"]' \
                 -c . -n pom.xml

and

$ xmlstarlet sel -N N="http://maven.apache.org/POM/4.0.0" \
                 -t -m '//N:dependency[N:groupId="com.mycompany.app"]/N:version' \
                 -c . -n pom.xml

Step 2: edit your file using the XPath you just created

Now it is time to perform the edit using the edit function in . Using the XPath earlier defined, we can easily update (-u) this one value (-v):

$ xmlstarlet ed -N N="http://maven.apache.org/POM/4.0.0" \
                -u '//N:dependency[N:groupId="com.mycompany.app"]/N:version' \
                -v "14.3" pom.xml > pom.new.xml

Step 3: verify and apply.

Verify the changes with diff or meld to check.

note: make your XPath knowledge as good as your Regex knowledge, this way you can skip step 1.

kvantour
  • 25,269
  • 4
  • 47
  • 72