2013-04-03 35 views
6

我想用Wix編輯XML文件。我正在使用與Wix 3.7捆綁在一起的WixUtilExtension。 xml文件是在Visual Studio 2010中爲C#應用程序創建的設置文件。在這個文件中,我使用了一個用於在數組中存儲多個字符串值的元素。這是不變的設置文件的內容:如何使用wix將多個元素添加到XML配置文件中?

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

我想<string>元素添加到<ArrayOfString>元素在這個文件中。一種方法是使用wix/UtilExtension命名空間中的<XmlConfig>元素。我已經加入該元素來保持這樣的配置文件中的分量:

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

這導致另外一個<string>元件到<ArrayOfString>元件。另一個<string>元素添加到設置文件,另一個XMLConfig的元素已被添加到一個不同的ID屬性設置項目的<Component>元素和序列更高的價值屬性是這樣的:

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

安裝後微星的,在設置文件中<ArrayOfString>元素看起來是這樣的:

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

我發現,這是可能的<XmlConfig>屬性的值屬性設置爲這樣的屬性值:

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

這很好。我希望用戶能夠動態地在安裝過程中添加多個值,以便將可變數量的<string>元素添加到設置文件中。 我的第一個方法是使用一個<?foreach?>聲明是這樣的:

<?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這個問題的唯一解決方案嗎?

回答

2

基於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; 
} 

這裏,在第一屬性字符串數組讀入一個局部變量將其轉化爲一個字符串數組。以下行建立到安裝程序使用的當前數據庫的連接。表XmlConfig上的句柄被創建,這是將XML元素添加到的表。要將正確的值插入該表中,最好創建一個包含此類表的安裝程序文件,然後在類似orca或InstEd的編輯器中查看該表。

在xpath中,反斜槓必須使用雙反斜槓進行轉義。 id變量保存臨時記錄的名稱,使用簡單的字符串和數字完美地工作。序列必須爲每個元素增加。我找不到關於flags列值的任何文檔,但是我發現它的值被設置爲273,而被創建的元素被設置爲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添加到安裝項目中。通過添加在安裝項目的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

0

是的,這是可能的,但如果你想在安裝時確定這個,那麼預處理器不是一個選項。預處理器在構建過程中執行。

爲了得到您想要的,您需要編寫另一個自定義操作,該操作將佔用任意長的一組用戶數據並將臨時行添加到XmlConfig表中。 src\ca\wcautil\wcawrap.cpp中的WcaAddTempRecord()函數可以完成這項工作。 src\ca\wixca\dll\RemoveFoldersEx.cpp是使用WcaAddTempRecord()RemoveFile表添加行的一個很好的例子。你會想要做類似的。

3

作爲除了BdN3504的答案...而不是整個

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

的事情。我會建議使用

<EnsureTable Id='XmlConfig' /> 

這確保了XMLConfig的表包含在輸出MSI,即使它是空的。 (我只是把這作爲一個評論..但我沒有明顯的聲望)

相關問題