2013-04-03 5 views
6

Ich versuche, eine XML-Datei mit Wix zu bearbeiten. Ich verwende die mit Wix 3.7 gebündelte WixUtilExtension. Die XML-Datei ist eine Einstellungsdatei, die in Visual Studio 2010 für eine C# -Anwendung erstellt wurde. In dieser Datei verwende ich ein Element, das zum Speichern mehrerer String-Werte in einem Array verwendet wird. Dies ist der Inhalt der unveränderten Einstellungsdatei:Wie können mehrere Elemente zu einer XML-Konfigurationsdatei mit wix hinzugefügt werden?

<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 <string> Elemente zum <ArrayOfString> Element in dieser Datei hinzufügen möchten. Eine Möglichkeit dazu besteht in der Verwendung eines <XmlConfig> Elements aus dem Wix/UtilExtension-Namespace. Ich habe dieses Element der Komponente hinzugefügt, die die Konfigurationsdatei wie folgt gilt:

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

Daraus ergibt sich die Zugabe von einem <string> Element zum <ArrayOfString> Element. So fügen Sie ein anderes <string> Element in die Einstellungsdatei, ein weiteres XMLConfig Element mit einem anderen ID-Attribut und einen höheren Wert für die Sequenz zu dem <Component> Element des Setup-Projekts hinzugefügt werden Attribut wie folgt aus:

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

Nach der Installation der msi, sieht das <ArrayOfString> Element in der Einstellungsdatei wie folgt aus:

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

ich habe herausgefunden, dass es möglich, den Wert Attribut eines <XmlConfig> Attribut auf den Wert einer Immobilie wie folgt festgelegt ist:

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

Das ist gut. Ich möchte, dass der Benutzer in der Lage ist, mehrere Werte dynamisch in den Installationsprozess einzufügen, so dass der Einstellungsdatei eine variable Anzahl von <string> Elementen hinzugefügt werden kann. Mein erster Ansatz war eine <?foreach?> Anweisung wie folgt zu verwenden:

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

ein paar Probleme mit diesem Ansatz sind:

  1. Die foreach-Anweisung verwendet eine Präprozessor Variable, die auf den Wert nicht eingestellt werden Ein Besitz.
  2. Der Wert des Attributs Sequence bleibt gleich.

ich den Benutzer die Werte für die Textelemente in einer Eigenschaft speichern möchten, die die Werte durch ein Semikolon und dann analysieren sie in einer foreach-Anweisung wie folgt trennt:

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

Dies führt den folgenden Fehler:

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. 

Gibt es eine Möglichkeit, eine variable Menge von Elementen mit dem XmlFile oder dem XmlConfig Element zu erstellen? Ist die einzige Lösung für dieses Problem eine CustomAction?

Antwort

2

Basierend auf Robs Antwort, hier ist mein neuer Ansatz zum Hinzufügen mehrerer Elemente zu einer XML-Konfigurationsdatei mit Wix. Ich wollte C++ Code nicht schreiben, deshalb habe ich DTF in meiner CustomAction verwendet.

Ich werde beschreiben, wie man eine Zeichenfolge, die mehrere Elemente enthält, mithilfe eines Trennzeichens in mehrere XML-Elemente umwandelt.

Zuerst muss eine Eigenschaft in der Setup-Datei enthalten sein, die die Zeichenfolge mit Trennzeichen enthält.

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

Diese Eigenschaft könnte natürlich vom Benutzer in einem Dialog ausgefüllt werden.

Als nächstes muss eine CustomAction geschrieben werden. Um das DTF zu verwenden, muss ein Verweis auf der Microsoft.Deployment.WindowsInstaller.dll dem C# CustomAction-Projekt hinzugefügt werden. Der Namespace Microsoft.Deployment.WindowsInstaller sollte mit einer using-Direktive in diesem Projekt enthalten sein. Mein Custom sieht wie folgt aus:

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

Hier zunächst die Objektstring in eine lokale Variable gelesen, die mit einem String-Array umgewandelt wird. Die folgende Zeile stellt eine Verbindung zur aktuellen Datenbank her, die vom Installationsprogramm verwendet wird. Ein Handle für die Tabelle XmlConfig wird erstellt. Dies ist die Tabelle, zu der die XML-Elemente hinzugefügt werden. Um die richtigen Werte in diese Tabelle einzufügen, ist es am besten, eine Installationsdatei zu erstellen, die eine solche Tabelle enthält, und dann diese Tabelle in einem Editor wie Orca oder InstEd zu betrachten.

Im Backend-Pfad müssen Backslashes mit doppelten Backslashes maskiert werden. Die ID-Variable enthält den Namen des temporären Datensatzes, wobei eine einfache Zeichenfolge verwendet wird und eine Zahl fehlerfrei funktioniert. Die Sequenz muss für jedes Element inkrementiert werden. Ich konnte keine Dokumentation zu den Werten der flags-Spalte finden, aber ich habe herausgefunden, dass der Wert für Elemente, die erstellt werden, auf 273 und für Elemente, die gelöscht werden, auf 289 gesetzt wird.

Sobald der Datensatz mit den richtigen Werten gefüllt ist, wird er mithilfe der InsertTemporary-Methode des Ansichtsobjekts zur XmlConfig-Tabelle hinzugefügt. Dies geschieht für jedes Element in der Zeichenfolge mit Trennzeichen.

Ein Problem, das mir begegnet ist, dass diese CustomAction fehlschlägt, wenn die XmlConfig-Tabelle nicht vorhanden ist. Um dieses Problem zu beheben, habe ich der Setup-Datei den folgenden Code hinzugefügt, der der XML-Datei ein Element hinzufügt und dieses Element sofort löscht. Ich denke, es könnte eine sauberere Lösung geben, aber das war die einfachste für mich.

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

Schließlich muss die CustomAction dem Setup-Projekt hinzugefügt werden.Durch Hinzufügen eines Verweises auf das Projekt Custom im Setup-Projekt, die Lage der binären wie folgt angegeben werden:

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

Die Custom sofort ausgeführt werden muss, sonst wird es nicht in der Lage sein, die Sitzung zugreifen Variable:

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

Um die richtige Position für die Custom in der Installationsreihenfolge zu bestimmen, ich verließ sich auf this article von Bob Arnson.

0

Ja, das ist möglich, aber wenn Sie dies zur Installationszeit haben wollen, dann ist der Präprozessor keine Option. Der Präprozessor wird während des Buildprozesses ausgeführt.

Um zu bekommen, was Sie wollen, müssen Sie eine weitere benutzerdefinierte Aktion schreiben, die den beliebig langen Satz von Benutzerdaten aufnimmt und der XmlConfig Tabelle temporäre Zeilen hinzufügt. Die WcaAddTempRecord() Funktion in src\ca\wcautil\wcawrap.cpp kann die Arbeit erledigen. Die src\ca\wixca\dll\RemoveFoldersEx.cpp ist ein ziemlich gutes Beispiel für die Verwendung von WcaAddTempRecord() zum Hinzufügen von Zeilen in die RemoveFile Tabelle. Du wirst das ähnlich machen wollen.

3

Als Ergänzung zu BdN3504 Antwort ... anstelle der gesamten

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

Sache. Ich würde die Verwendung von

<EnsureTable Id='XmlConfig' /> 

vorschlägt Dies stellt sicher, dass die XMLConfig Tabelle in der Ausgabe MSI enthalten ist, auch wenn er leer ist. (Ich hätte dies nur als Kommentar .. aber ich habe nicht den Ruf anscheinend)

Verwandte Themen