65.9K
CodeProject 正在变化。 阅读更多。
Home

版本资源工具使用 XML/XSLT 和 .NET

starIconstarIconstarIconstarIconstarIcon

5.00/5 (7投票s)

2002年10月25日

7分钟阅读

viewsIcon

65776

downloadIcon

496

一个用于自动更新 C++、C# 和其他项目版本资源的工具

Sample Image

摘要

本文我想探讨两个主题:一个是教育性的,另一个是实践性的。我的教育性原因是向您展示如何利用 XMLXSL .NET Framework 类来完成一些非琐碎的任务。通过这样做,我将向您展示一种解决自动夜间构建中更新版本号的实际问题的途径;特别是针对 C++ 和 C# 项目。由于使用了 XSL,该解决方案是开放式的,因此您只需稍加修改即可将其用于任何语言或项目。

版本资源

如果您一直是 Microsoft Windows 开发者,那么您一定遇到过在产品每次主要构建后更新二进制文件版本号的问题。每次构建后递增版本号可以很好地将问题定位到特定构建。此外,良好的版本号对于您的安装程序能够覆盖或与现有产品副本并存至关重要。

如果您遵循良好的软件开发原则,并尝试每天自动进行一次完整构建,那么您很可能已经找到了某种自动更新版本号的方法。如果没有,或者您对现有解决方案不满意,那么今天就是您的幸运日!

详细说明

该工具包含一个名为 MKVER2.EXE 的可执行文件。如果您查看源代码,所有重要的代码都包含在 MainClass 中。应用程序的数据流如下所示:

VRT Data Flow

一个扩展名为 PVD(用于产品版本数据)的 XML 文件包含您产品中 **所有** 二进制文件的所有相关版本信息。此文件是 MKVER2 的第一个输入。您还将指定输出文件的名称,在图表中,它是 AssemblyInfo.cs。我实现的算法是,我们使用输出文件的 **扩展名** 来搜索一个相应的 XSL 转换文件,其文件名是 version.extension.xsl。因此,AssemblyInfo.cs 会导致我们使用 version.cs.xsl 作为 MKVER2 的第二个输入。

这些模板按以下顺序在各种位置查找:

  1. 在命令行中指定的目录
  2. MKVER_TEMPLATES 环境变量指定的目录
  3. 当前目录下的 Templates 子目录
  4. MKVER.EXE 所在目录下的 Templates 子目录

查看 PVD 文件的格式,您会发现它相当简单。可能需要解释的一点是 <VersionInfo> 元素。

      <VersionInfo lang="1033" charset="1200">
        ...
        ...
      </VersionInfo>

这里的想法是,所有特定于语言的版本信息(如版权、描述、商标等)都包含在这些元素中。使用命令行参数,您可以确定哪些语言的 string 会出现在您的版本资源中。查看 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">

正如您所见,我们使用 XSL 参数将此信息传递到转换中。稍后在转换中,我们将这些参数用作 XPath 查询的输入,该查询检索特定的 VersionInfo 元素。

    <xsl:apply-templates select=
                   "VersionInfo[@lang=$lang and @charset=$charset]" mode="FileVersion"/>

mode 属性的使用是因为我有两个 FileVersion 模板,一个用于产品 VersionInfo,另一个用于文件 VersionInfo。以下代码展示了 MainClass.csMKVER2 算法的核心部分。

    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);
    }

首先,我们获取输入文档并将其加载到 XmlDocument 对象中。快速检查预期的 revision 属性后,我们继续执行 UpdateProductVersion() 函数来递增/设置新版本号。

AddNodes() 函数的作用是什么?嗯,有时在输出中,我们希望包含一些从输入数据派生的数据,但这些数据格式不正确,不易访问。例如,假设您的版本号当前是 1.0.0.100。100 可能指您当前的构建号。假设您想自动发送一封电子邮件,上面写着“Build 100 Completed”。您如何获取版本号的“100”部分?我提出的解决方案是让 MKVER2 预先计算某些信息,并将它们作为新元素添加到原始 XML 中。这使得 XSL 转换中的工作 **容易得多**

为了让无法访问源代码的人能够轻松地看到可用的新元素,我添加了 -trace 命令行选项,该选项会将新的 XML 数据转储到屏幕上。动态添加元素的这种方法的缺点是它会在 MKVER 和输入数据的格式之间产生强耦合。我们查找某些元素来作为新节点的基础。因此,前面提到的 revision 检查是必需的。

最后一步是调用 TransformDocument() 来实际执行 XSL 转换。这将创建我们的输出文件。

使用工具

您如何使用该工具?嗯,您可能注意到 MKVER2 使用 MKVER2 来执行其自身的版本控制!示例源代码解决方案文件中包含几个 Makefile 项目。名为 Version 的项目会在执行完整 Release 配置构建时调用一个批处理文件来更新 MKVER2 的版本。该批处理文件使用 4NT 编写,展示了我如何更新 MKVER2 的版本号并将其检查到本地 Perforce 版本控制数据库。除非您拥有 4NT 和 Perforce,否则您将无法运行它,但您可以足够轻松地遵循基本步骤。

关于 C# 项目,我发现一个我不喜欢的方面是,似乎没有任何方法可以实现 C++ 的 include 功能。除非您从命令行构建,否则您甚至无法在 VS.NET 中拥有一个包含项目目录以外的文件的 C# 项目。这基本上意味着您必须单独更新每个项目的版本信息。另请注意,这就是为什么您必须指定 -name 命令行参数,以便您的 C# 输出文件只包含一个项目的版本信息。

是的,我知道 .NET 项目可以自动创建自己的版本号,如果您使用像 [assembly: AssemblyVersion("1.0.*")] 这样的属性。但这本质上会为版本号生成一个随机数,我觉得这就像用尖锐的棍子戳眼睛一样没用。

对于 C++ 项目,您会更轻松一些。您可以创建一个共享位置的 #include 文件,并仅生成该文件。您可以在每个 C++ 项目中设置一个预处理器宏,并选择与该项目相关的版本信息。因此,无需为 MKVER2 指定 -name 参数(除非您想这样做)。请查看 version.h.xsl 以获取更多信息,或者只需在提供的 version.pvd 上运行 MKVER2 即可查看一些示例输出。我包含了一个 version.rc2 文件,您可以将其包含在 C++ 项目的 RC 文件中,以利用在头文件中生成的 #defines。要将此 RC2 添加到您的项目中,请将其复制到项目目录,打开您的 RC 文件,然后选择 **Edit Resource Includes...**。然后在“**Compile-time directives:**”编辑器中,添加行 #include "version.rc2"

您还可以使用 MKVER2 生成任何您喜欢的包含版本信息的其他类型的输出。我包含了一些 XSL 文件,用于生成 BAT 和 HTML 文件,供您进行版本控制。

结论

好的,如果您阅读本文是为了学习如何用 XSL 或 .NET 编程,您现在可能会有些失望。我建议您将本文存档以备将来参考。但是,如果您已经掌握了 XML 和 XSL 的基础知识,并且正在寻找一个强大的示例来真正展示您可以从中获得的一些有用功能,您应该会更满意。我被 .NET 中处理 XML 相关事务的简易性所折服。我过去使用 COM 接口编写了大量的 MSXML 代码,而且我再也不会回去了!

至于版本实用程序,我希望它对您有用。如果有人为 VB.NET、Java/J# 或任何其他可版本化的项目编写 XSL 转换并将它们发送给我,我很乐意将它们添加到此页面上的 MKVER2 下载中。最后,如果您还没有找到,并且正在寻找 XSL 在 .NET Framework 中的一个令人惊叹的应用,请查看 NDoc

许可证

本文没有明确的许可附加,但可能包含文章文本或下载文件本身的使用条款。如有疑问,请通过下方的讨论板联系作者。您可以在 此处 找到作者可能使用的许可列表。

© . All rights reserved.