Regexp: Substituting a version number in an XML file

Tags: ant regex java
Question!

Ok I give up, I've been trying to write a regexp in ant to replace the version number from something that I have in a properties file. I have the following:

<?xml version="1.0" encoding="UTF-8"?>
    <feature
          id="some.feature.id"
          label="Some test feature"
          version="1.0.0"
          provider-name="Provider">

   <plugin
         id="test.plugin"
         download-size="0"
         install-size="0"
         version="0.0.0"
         unpack="false"/>
..... many plugins later....
</feature>

What I want to achieve is substitute the version number of the feature tag only, without changing the version of the xml or the version of the miriad of plugins in the file.

The problem I have is that I either match too much or too little. Definitively matching "version" is not enough, because everything would be changed

Is there any easy way to match then only the version inside the tag, taking into consideration that the '0.0.0' could be any number?



Answers

It might be a little heavyweight, but since you're dealing with XML, I would recommend using an XSLT like this:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:template match="@*|*">
    	<xsl:copy>
    		<xsl:apply-templates select="node()|@*|*"/>
    	</xsl:copy>
    </xsl:template>


    <xsl:template match="/feature/@version">
    	<xsl:attribute name="version">
    		<xsl:text>1.0.1</xsl:text>
    	</xsl:attribute>
    </xsl:template>
</xsl:stylesheet>


Just for fun: a one-liner, using xpath(!), with ruby

(I know: it is not a regexp, but it is meant to illustrate the suggestion of Will, who is saying

Now, since you're doing this with XML, the obvious question is, "Why aren't you using XPath?

)

type 'irb', then:
require "rexml/document";include REXML;file = File.new("a.xml"); doc = Document.new(file);puts doc; doc.elements.each("/feature") {|e| e.attributes["version"]="1.2.3" }; puts doc

It replaces all 'version' attributes of all 'feature' elements with "1.2.3"

irb(main):001:0* require "rexml/document";include REXML;file = File.new("a.xml"); doc = Document.new(file);puts doc; doc.elements.each("/feature") {|e| e.attributes["version"]="1.2.3" }; puts doc

<?xml version='1.0' encoding='UTF-8'?>
<feature id='some.feature.id' version='1.0.0' provider-name='Provider' label='Some test feature'>
   <plugin unpack='false' id='test.plugin' download-size='0' version='0.0.0' install-size='0'/>
</feature>


<?xml version='1.0' encoding='UTF-8'?>
<feature id='some.feature.id' version='1.2.3' provider-name='Provider' label='Some test feature'>
   <plugin unpack='false' id='test.plugin' download-size='0' version='0.0.0' install-size='0'/>
</feature>
By : VonC


The following regex may do what you want...

(?<=<feature[^>]{*,1000}version=")[^"]*(?=")

Which, in human speak, roughly means

I want to match text that immediately follows the string "<feature", followed by up to a thousand characters not the greater-than bracket, and "version=""; the text to match is immediately followed by a double quote, and contains no double quotes.

**Thanks to Alan M for the heads up about java lookbehinds ಠ_ಠ

If you use this regex with a Replace operation, it will switch out whatever is inside the version="" attribute with whatever you set as the replacement value. Its up to you to provide the correctly formatted version number.

Now, since you're doing this with XML, the obvious question is, "Why aren't you using XPath?"

By : Will


This video can help you solving your question :)
By: admin