![]() |
Languages »
XML »
XML/XSLT
Intermediate
Version Resource Tool Using XML/XSLT and .NETBy John Lyon-SmithA tool for automatically updating version resources in C++, C# and other projects. |
C#, Windows, .NET 1.0, Dev
|
|
Advanced Search |
|
|
|
||||||||||||||||

I want to address two topics in this article, one educational and the other practical. My educational reason is to show you how to do something non-trivial utilizing the XML and XSL .NET Framework classes. In doing this I'm going to show you one approach to solving the practical problem of updating version numbers in automated nightly builds; in particular of C++ and C# projects. Because of the use of XSL the solution is open ended, so you can use for any language or project, with only a little extra work.
If you've been a Microsoft Windows developer long enough, you've had to solve the problem of updating your binaries version numbers after each major build of your product. Incrementing the version number after each build gives you an excellent way to localize problems to particular builds. Also, having good version numbers is essential for your installer to be able to install over or alongside existing copies of your product.
If you practice good software development principles and try and do a full build automatically every day, there's a good chance you'll have figured out some automated way to do the updates. If not, or if you are not happy with your existing solution, today is your lucky day!
The tool consists of a single executable called MKVER2.EXE.
If you're looking at the source, the important code is all contained in MainClass.
The data flow through the application looks like this:

An XML file with an extension PVD (for Product Version Data) contains all the
relevant version information for all the binary files in your
product. This file is the first input into MKVER2. You'll
also specify the name of the output file, in the diagram it's AssemblyInfo.cs.
The algorithm I have implemented is that we use the extension of the
output file to search for a corresponding XSL transform file with the filename
of version.extension.xsl. Hence, AssemblyInfo.cs
causes us to use version.cs.xsl as the second input to
MKVER2.
These templates are looked for in the following various locations in order (1)
the directory specified on the command line, (2) the directory specified by the
MKVER_TEMPLATES environment variable, (3) a Templates
sub-directory of the current directory, (4) a Templates sub-directory
of the directory where MKVER.EXE is located.
Take a look at the format of a PVD file and you'll see it's pretty
straightforward. One thing that might take some explaining are the <VersionInfo>
elements:
<VersionInfo lang="1033" charset="1200">
...
...
</VersionInfo>
The idea here is that all language specific pieces of version information, such
as copyrights, descriptions, trademarks, etc. are contained within these
elements. Using command line parameters you can determine which language
strings end up in your version resources. Take a look at the first part
of version.cs.xsl:
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="text" version="4.0" encoding="utf-8"/>
<xsl:param name="lang"/>
<xsl:param name="charset"/>
<xsl:param name="name"/>
<xsl:template match="/VersionData">
As you can see we make use of XSL parameters to pass this information into the
transform. Later on in the transform we use these parameters as input to
the XPath query that retrieves a specific VersionInfo element:
<xsl:apply-templates select=
"VersionInfo[@lang=$lang and @charset=$charset]" mode="FileVersion"/>
The mode attribute is used because I have two FileVersion
templates, one for the product VersionInfo and one for the files
VersionInfo. The following code shows the guts of the MKVER2
algorithm in MainClass.cs:
try
{
inputFile = Path.GetFullPath((string)inputFile);
// load the version data
document.Load(inputFile);
// wrap it with an XmlNavigator
navigator = document.CreateNavigator();
if (!IsCorrectRevision(1))
return;
UpdateProductVersion();
// Add dynamically generated nodes
AddNodes();
if (trace)
{
XmlTextWriter xw = new XmlTextWriter(BpConsole.Out);
xw.Formatting = Formatting.Indented;
document.WriteContentTo(xw);
xw.Flush();
BpConsole.WriteLine();
}
TransformDocument();
}
catch (Exception e)
{
WriteMessage(MessageType.Error, e.Message);
}
First we grab the input document and load it into an XmlDocument object.
A quick check for the expected revision attribute and we proceed to the
UpdateProductVersion() function to increment/set the new version
number.
What is the function of AddNodes()? Well, sometimes
in the output we are going to want some data that is derived from the
input data, but is not in the correct format to make it easily
accessible. For example, let's say your version number is currently
1.0.0.100. The 100 might refer to your current build number. Let's
say you want to automatically send an e-mail stating "Build 100
Completed". How do you get at the "100" part of the version number?
The solution I came up with was to have MKVER2 pre-calculate certain pieces of
information and add them as new elements into the original XML. This
makes things much easier in the XSL transformations.
In order that someone who doesn't have access to the source code can
easily see what these new elements are available, I added the -trace
command line option, which dumps the new XML data to the screen. One
downside of the approach of dynamically adding elements is that it creates a
strong coupling between MKVER and the format of the input data. We look
for certain elements to base our new nodes on. Hence the revision check
mentioned earlier.
The final step is to call TransformDocument() to actually
do the XSL transformation. This creates our output file.
How do you use the tool? Well you you've noticed MKVER2 uses MKVER2 to do
it's own versioning! Included in the sample source code solution file are
a couple of Makefile projects. The one called Version simply
invokes a batch file to update the version of MKVER2 whenever a full Release
configuration build is performed. The batch file is written using
4NT, and shows how I update the version number of MKVER2 and check the
results into a local Perforce version
control database. Unless you have 4NT and Perforce you won't be able to
run it, but you'll be able to follow the basic steps easily enough.
One thing I've discovered about C# projects that I'm not thrilled about is that
there does not appear to be any way at all to do the equivalent of C++
includes. Unless you build from the command line you can't even have a C#
project in VS.NET that includes files in directories other than the project
directory. What this basically means is you'll have to go through
each project and update the version information separately. Note also
that this is why you have to specify a -name command line
parameter, so that your C# output file only contains version information for
one project.
Yes, I know that .NET projects can automatically create version numbers for
themselves, if you use an attribute like [assembly:
AssemblyVersion("1.0.*")]. But this essentially generates a
random number for the version number, which I feel is about as useful a poke in
the eye with a sharp stick.
For C++ projects, you'll have things easier. You can create an
#include file in a shared location and generate just that one
file. You can set a preprocessor macro in each C++ project and select the
version information that's relevant to that project. Hence, no need to
specify a -name parameter to MKVER2 (unless you want to that
is). Check out version.h.xsl for more information, or just
run MKVER2 on the supplied version.pvd to see some
example output. I've included a version.rc2 file that you can
include in your C++ projects RC file to make use of the #define's
generated in the header file. To add this RC2 to your project copy it
into the project directory, open your RC file and select Edit Resource
Includes... Then in the "Compile-time directives:" editor add the
line #include "version.rc2".
You can also use MKVER2 to generate any other type of output you like containing the version information. I've include some XSL files for generating BAT and HTML files for your versioning pleasure.
OK, if you read this article to learn how to program in XSL or .NET your probably a bit disappointed by now. I suggest you store this article away for future reference. However, if you have already mastered the basics of XML and XSL and were looking for a power sample to really show you some of the things you can usefully do with it, you should be happier. I'm blown away by how easy it is to do XML related stuff in .NET. I've written a fair amount of MSXML code using the COM interfaces in the past, and I'm never going back!
As far as the version utility goes, I hope it's useful to you. If someone writes XSL transforms for VB.NET, Java/J# or any other versionable project and sends them to me, I'd be happy to add them to the MKVER2 download on this page. Finally, if you haven't found it yet and you are looking for a knock your socks off application of XSL with the .NET Framework check out NDoc.
| You must Sign In to use this message board. | ||||||||||||||||||||||
|
||||||||||||||||||||||
|
||||||||||||||||||||||
|
||||||||||||||||||||||
|
||||||||||||||||||||||
General
News
Question
Answer
Joke
Rant
Admin
|
PermaLink |
Privacy |
Terms of Use
Last Updated: 24 Oct 2002 Editor: Chris Maunder |
Copyright 2002 by John Lyon-Smith Everything else Copyright © CodeProject, 1999-2009 Web11 | Advertise on the Code Project |