【问题标题】:How can multiple elements be added to an XML config file with wix?如何使用 wix 将多个元素添加到 XML 配置文件中?
【发布时间】:2014-08-26 21:56:53
【问题描述】:

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

<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>

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

<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>

这会导致向&lt;ArrayOfString&gt; 元素添加一个&lt;string&gt; 元素。要将另一个 &lt;string&gt; 元素添加到设置文件中,必须将另一个 XmlConfig 元素添加到安装项目的 &lt;Component&gt; 元素中,该元素具有不同的 Id 属性和更高的 Sequence 属性值,如下所示:

<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"
/>

安装 msi 后,设置文件中的&lt;ArrayOfString&gt; 元素如下所示:

<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>

我发现可以将 &lt;XmlConfig&gt; 属性的 Value 属性设置为如下属性的值:

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

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

<?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?>

这种方法存在一些问题:

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

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

<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?>

这会引发以下错误:

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.

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

【问题讨论】:

    标签: wix app-config elements


    【解决方案1】:

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

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

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

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

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

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

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

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

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

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

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

    <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" />
    

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

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

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

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

    为了确定安装顺序中 CustomAction 的正确位置,我依赖于 Bob Arnson 的 this article

    【讨论】:

    • 我建议不要使用整个虚拟 XmlConfig 条目,而只使用 EnsureTable 条目 XML &lt;EnsureTable Id='XmlConfig' /&gt; 这可确保 XmlConfig 表包含在输出 MSI 中,即使它是空的。跨度>
    【解决方案2】:

    是的,这是可能的,但如果您想在安装时确定这一点,则预处理器不是一个选项。预处理器在构建过程中执行。

    要获得所需的内容,您需要编写另一个自定义操作,该操作采用任意长的用户数据集并将临时行添加到XmlConfig 表中。 src\ca\wcautil\wcawrap.cpp 中的 WcaAddTempRecord() 函数可以完成这项工作。 src\ca\wixca\dll\RemoveFoldersEx.cpp 是使用WcaAddTempRecord()RemoveFile 表添加行的一个很好的例子。你会想要做类似的事情。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-01-04
      • 2014-09-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-08-02
      • 1970-01-01
      相关资源
      最近更新 更多