如何使用 wix 将多个元素添加到 XML 配置文件中? [英] How can multiple elements be added to an XML config file with wix?

查看:21
本文介绍了如何使用 wix 将多个元素添加到 XML 配置文件中?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用 Wix 编辑 XML 文件.我正在使用与 Wix 3.7 捆绑在一起的 WixUtilExtension.xml 文件是在 Visual Studio 2010 中为 C# 应用程序创建的设置文件.在此文件中,我使用了一个元素,该元素用于在数组中存储多个字符串值.这是未更改的设置文件的内容:

<预><代码><配置><应用程序设置><AppName.Properties.Settings><setting name="StringArray" serializeAs="Xml"><价值><ArrayOfString xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:xsd="http://www.w3.org/2001/XMLSchema"></ArrayOfString></设置></AppName.Properties.Settings></applicationSettings></配置>

我想将 元素添加到此文件中的 元素.一种方法是使用 wix/UtilExtension 命名空间中的 元素.我已将此元素添加到包含如下配置文件的组件中:

<File Source="SettingsFile.exe.config" KeyPath="yes" Id="FILE_config"/><util:XmlConfig名称=字符串"价值=我的价值"File="[INSTALLFOLDER]SettingsFile.exe.config"Id="字符串 1"在=安装"行动=创建"节点=元素"ElementPath="/configuration/applicationSettings/AppName.Properties.Settings/setting[\[]@name='StringArray'[\]]/value/ArrayOfString"序列="100"/></组件>

这导致向 元素添加一个 元素.要将另一个 元素添加到设置文件中,必须将另一个 XmlConfig 元素添加到具有不同 Id 属性的安装项目的 元素中以及更高的 Sequence 属性值,如下所示:

安装 msi 后,设置文件中的 元素如下所示:

<string>我的值</string><string>我的第二个值</string></ArrayOfString>

我发现可以将 <XmlConfig> 属性的 Value 属性设置为这样的属性值:

<util:XmlConfig Value="[STRING1VALUE]" .../>

这很好.我希望用户能够在安装过程中动态添加多个值,以便可以将可变数量的 元素添加到设置文件中.我的第一种方法是使用这样的 语句:

这种方法存在一些问题:

  1. foreach 语句使用无法设置为属性值的预处理器变量.
  2. Sequence 属性的值保持不变.

我希望用户将字符串元素的值存储在一个属性中,该属性用分号分隔这些值,然后在像这样的 foreach 语句中解析它们:

<?[VALUES] 中的 foreach 值?><util:XmlConfig名称=字符串"值="$(var.value)"File="[INSTALLFOLDER]SettingsFile.exe.config"Id="String$(var.value)"在=安装"行动=创建"节点=元素"ElementPath="/configuration/applicationSettings/AppName.Properties.Settings/setting[\[]@name='StringArray'[\]]/value/ArrayOfString"序列="101"/><?endforeach?>

这会引发以下错误:

util:XmlConfig/@Id 属性的值String[VALUES]"不是合法标识符.标识符可以包含 ASCII 字符 A-Z、a-z、数字、下划线 (_) 或句点 (.).每个标识符必须以字母或下划线开头.

有什么方法可以使用 XmlFile 或 XmlConfig 元素创建可变数量的元素?这个问题的唯一解决方案是 CustomAction 吗?

解决方案

根据 Rob 的回答,这是我使用 Wix 将多个元素添加到 XML 配置文件的新方法.我不想写 C++ 代码,这就是为什么我使用 DTF 在我的 CustomAction 中.

我将描述如何使用分隔符将包含多个元素的字符串转换为多个 XML 元素.

首先需要在设置文件中有一个包含分隔字符串的属性.

当然,这个属性可以由用户在对话框中填充.

接下来,必须编写一个 CustomAction.要使用 DTF,必须向 C# CustomAction 项目添加对 Microsoft.Deployment.WindowsInstaller.dll 的引用.命名空间 Microsoft.Deployment.WindowsInstaller 应包含在该项目中的 using 指令中.我的 CustomAction 看起来像这样:

[CustomAction]公共静态 ActionResult 插入(会话会话){string strings = session["STRINGARRAY"];string[] stringArray = strings.Split(';');数据库 db = session.Database;View view = db.OpenView("select * from `XmlConfig`");string xpath = "/configuration/applicationSettings/AppName.Properties.Settings/setting[\\[]@name='StringArray'[\\]]/value/ArrayOfString";for (int i = 0; i < stringArray.Length; i++){string id = String.Format("String{0}", i);整数序列 = 100 + i;字符串值 = stringArray[i].Trim();记录记录 = 新记录(ID,"[INSTALLFOLDER]SettingsFile.exe.config",路径,空值,细绳",价值,273,"产品组件",序列);view.InsertTemporary(rec);}数据库关闭();返回 ActionResult.Success;}

在这里,首先将属性 StringArray 读入一个局部变量,该变量被转换为字符串数组.以下行建立与安装程序使用的当前数据库的连接.创建了表 XmlConfig 上的句柄,该表是添加 XML 元素的表.要将正确的值插入到该表中,最好创建一个包含此类表的安装程序文件,然后在 orca 或 InstEd 等编辑器中查看该表.

在 xpath 中,必须使用双反斜杠来转义反斜杠.id 变量保存临时记录的名称,使用一个简单的字符串和一个数字可以完美地工作.必须为每个元素递增序列.我找不到关于 flags 列值的任何文档,但我发现它的值对于创建的元素设置为 273,对于删除的元素设置为 289.

一旦记录填充了正确的值,就会使用视图对象的 InsertTemporary 方法将其添加到 XmlConfig 表中.这是针对分隔字符串中找到的每个元素完成的.

我遇到的一个问题是,如果 XmlConfig 表不存在,则此 CustomAction 会失败.为了解决这个问题,我在设置文件中添加了以下代码,该代码将一个元素添加到 XML 文件并立即删除该元素.我想可能有更简洁的解决方案,但这对我来说是最简单的.

<util:XmlConfig在=安装"行动=删除"Id="DeleteDummyEntry"节点=元素"File="[INSTALLFOLDER]SettingsFile.exe.config"VerifyPath="/configuration/applicationSettings/AppName.Properties.Settings/setting[\[]@name='StringArray'[\]]/value/ArrayOfString/string"ElementPath="/configuration/applicationSettings/AppName.Properties.Settings/setting[\[]@name='StringArray'[\]]/value/ArrayOfString"序列="2"/>

最后,必须将 CustomAction 添加到安装项目中.通过在 setup 项目中添加对 CustomAction 项目的引用,可以像这样指定二进制文件的位置:

CustomAction 必须立即执行,否则将无法访问会话变量:

<CustomAction Id="CA_XmlCustomAction" BinaryKey="XmlCustomActionDLL" DllEntry="Insert" Execute="immediate" Return="check"/><安装执行序列><Custom Action="CA_XmlCustomAction" Before="RemoveRegistryValues"/></InstallExecuteSequence>

为了确定 CustomAction 在安装顺序中的正确位置,我依赖于 这篇文章 作者:鲍勃·阿恩森.

I am trying to edit an XML file with Wix. I am using the WixUtilExtension bundled with Wix 3.7. The xml file is a settings file created in Visual Studio 2010 for a C# application. In this file, I am using an element which is used to store multiple string values in an array. This is the content of the unaltered settings file:

<configuration>
    <applicationSettings>
        <AppName.Properties.Settings>
            <setting name="StringArray" serializeAs="Xml">
                <value>
                    <ArrayOfString xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                        xmlns:xsd="http://www.w3.org/2001/XMLSchema">
                    </ArrayOfString>
                </value>
            </setting>
        </AppName.Properties.Settings>
    </applicationSettings>
</configuration>

I want to add <string> elements to the <ArrayOfString> element in this file. One way to do this is by using an <XmlConfig> element from the wix/UtilExtension namespace. I have added this element to the component which holds the config file like this:

<Component Id="ProductComponent" Guid="$(var.ConfigGuid)">
    <File Source="SettingsFile.exe.config" KeyPath="yes" Id="FILE_config" />
    <util:XmlConfig
      Name="string"
      Value="My value"
      File="[INSTALLFOLDER]SettingsFile.exe.config"
      Id="String1"
      On="install"
      Action="create"
      Node="element"
      ElementPath="/configuration/applicationSettings/AppName.Properties.Settings/setting[\[]@name='StringArray'[\]]/value/ArrayOfString"
      Sequence="100"
      />
</Component>

This results in the addition of one <string> element to the <ArrayOfString> element. To add another <string> element to the settings file, another XmlConfig element has to be added to the <Component> element of the setup project with a different Id attribute and a higher value for the Sequence attribute like this:

<util:XmlConfig
    Name="string"
    Value="My second value"
    File="[INSTALLFOLDER]SettingsFile.exe.config"
    Id="String2"
    On="install"
    Action="create"
    Node="element"
    ElementPath="/configuration/applicationSettings/AppName.Properties.Settings/setting[\[]@name='StringArray'[\]]/value/ArrayOfString"
    Sequence="101"
/>

After installation of the msi, the <ArrayOfString> element in the settings file looks like this:

<ArrayOfString xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                            xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<string>My value</string><string>My second value</string></ArrayOfString>

I have found out that it is possible to set the Value attribute of an <XmlConfig> attribute to the value of a property like this:

<Property Id="STRING1VALUE" Value="My value" />
<util:XmlConfig Value="[STRING1VALUE]" ... />

This is good. I would like the user to be able to add multiple values in the installation process dynamically so that a variable amount of <string> elements can be added to the settings file. My first approach was to use a <?foreach?> statement like this:

<?define values="My value;My second value"?>
<?foreach value in $(var.values)?>
    <util:XmlConfig
        Name="string"
        Value="$(var.value)"
        File="[INSTALLFOLDER]SettingsFile.exe.config"
        Id="String$(var.value)"
        On="install"
        Action="create"
        Node="element"
        ElementPath="/configuration/applicationSettings/AppName.Properties.Settings/setting[\[]@name='StringArray'[\]]/value/ArrayOfString"
        Sequence="101"
    />
<?endforeach?>

There are a few problems with this approach:

  1. The foreach statement uses a preprocessor variable which cannot be set to the value of a property.
  2. The value of the Sequence attribute stays the same.

I would like the user to store the values for the string elements in a Property which separates the values by semicolons and then parse them in a foreach statement like this:

<Property Id="VALUES" Value="My value;My second value" />
<?foreach value in [VALUES]?>
    <util:XmlConfig
        Name="string"
        Value="$(var.value)"
        File="[INSTALLFOLDER]SettingsFile.exe.config"
        Id="String$(var.value)"
        On="install"
        Action="create"
        Node="element"
        ElementPath="/configuration/applicationSettings/AppName.Properties.Settings/setting[\[]@name='StringArray'[\]]/value/ArrayOfString"
        Sequence="101"
    />
<?endforeach?>

This throws the following error:

The util:XmlConfig/@Id attribute's value, 'String[VALUES]', is not a legal identifier. 
Identifiers may contain ASCII characters A-Z, a-z, digits, underscores (_), or periods (.). 
Every identifier must begin with either a letter or an underscore.

Is there any way I can create a variable amount of elements with the XmlFile or the XmlConfig element? Is the only solution to this problem a CustomAction?

解决方案

Based on Rob's answer, here is my new approach to adding multiple elements to an XML config file with Wix. I did not want to write C++ code, that is why I used DTF in my CustomAction.

I am going to describe how to turn a string containing multiple elements using a delimiter into multiple XML elements.

First there needs to be a property in the setup file containing the delimited string.

<Property Id="STRINGARRAY" Value="string1;string2;string3" />

This property could be populated by the user in a dialog, of course.

Next, a CustomAction has to be written. To make use of the DTF, a reference to the Microsoft.Deployment.WindowsInstaller.dll has to be added to the C# CustomAction project. The namespace Microsoft.Deployment.WindowsInstaller should be included with a using directive in that project. My CustomAction looks like this:

[CustomAction]
public static ActionResult Insert(Session session)
{
    string strings = session["STRINGARRAY"];
    string[] stringArray = strings.Split(';');
    Database db = session.Database;
    View view = db.OpenView("select * from `XmlConfig`");
    string xpath = "/configuration/applicationSettings/AppName.Properties.Settings/setting[\\[]@name='StringArray'[\\]]/value/ArrayOfString";
    for (int i = 0; i < stringArray.Length; i++)
    {
        string id = String.Format("String{0}", i);
        int sequence = 100 + i;
        string value = stringArray[i].Trim();
        Record rec = new Record(
            id,
            "[INSTALLFOLDER]SettingsFile.exe.config",
            xpath,
            null,
            "string",
            value,
            273,
            "ProductComponent",
            sequence);
        view.InsertTemporary(rec);
    }
    db.Close();
    return ActionResult.Success;
}

Here, at first the Property StringArray is read into a local variable which is converted to a string array. The following line establishes a connection to the current database used by the installer. A handle on the table XmlConfig is created, which is the table where the XML elements are added to. To insert the right values into that table, it is best to create an installer file which contains such a table and then take a look at that table in an editor like orca or InstEd.

In the xpath, backslashes have to be escaped by using double backslashes. The id variable holds the name of the temporary record, using a simple string and a number works flawlessly. The sequence has to be incremented for each element. I could not find any documentation on the values of the flags column, but I have found out that its value is set to 273 for elements that are created and 289 for elements that get deleted.

Once the record is filled with the correct values, it gets added to the XmlConfig table by using the InsertTemporary method of the view object. This is done for each element found in the delimited string.

A problem I have come across is that this CustomAction fails, if the XmlConfig table does not exist. To counter this problem I have added the following code to the setup file, which adds an element to the XML file and immediately deletes that element. I guess there could be a cleaner solution, but this was the easiest one for me.

<util:XmlConfig
    Name="string"
    Value="Dummy"
    File="[INSTALLFOLDER]SettingsFile.exe.config"
    Id="DummyEntry"
    On="install"
    Action="create"
    Node="element"
    ElementPath="/configuration/applicationSettings/AppName.Properties.Settings/setting[\[]@name='StringArray'[\]]/value/ArrayOfString"
    Sequence="1" />
<util:XmlConfig
    On="install"
    Action="delete"
    Id="DeleteDummyEntry"
    Node="element"
    File="[INSTALLFOLDER]SettingsFile.exe.config"
    VerifyPath="/configuration/applicationSettings/AppName.Properties.Settings/setting[\[]@name='StringArray'[\]]/value/ArrayOfString/string"
    ElementPath="/configuration/applicationSettings/AppName.Properties.Settings/setting[\[]@name='StringArray'[\]]/value/ArrayOfString"
    Sequence="2" />

Finally, the CustomAction has to be added to the setup project. By adding a reference to the CustomAction project in the setup project, the location of the binary can be specified like this:

<Binary Id="XmlCustomActionDLL" SourceFile="$(var.XmlCustomAction.TargetDir)XmlCustomAction.CA.dll" />

The CustomAction has to be executed immediately, otherwise it won't be able to access the session variable:

<CustomAction Id="CA_XmlCustomAction" BinaryKey="XmlCustomActionDLL" DllEntry="Insert" Execute="immediate" Return="check" />
<InstallExecuteSequence>
  <Custom Action="CA_XmlCustomAction" Before="RemoveRegistryValues" />
</InstallExecuteSequence>

To determine the right position for the CustomAction in the installation sequence, I relied on this article by Bob Arnson.

这篇关于如何使用 wix 将多个元素添加到 XML 配置文件中?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆