This documentation is archived and is not being maintained.

Automating the Deployment of an InfoPath 2003 Form Template

Office 2003

This content is no longer actively maintained. It is provided as is, for anyone who may still be using these technologies, with no warranties or claims of accuracy with regard to the most recent product version or service release.

Summary: Microsoft Office InfoPath 2003 enables you to publish form templates to a specific location, such as a Web server or a network file share. In this article, learn how to update part of a previously-published form template and move it to a new location. (11 printed pages)

Shiraz Cupala, Joshua Bell, Mike Talley

Microsoft Corporation

August 2005

Applies to: Microsoft Office InfoPath 2003

Contents

When moving a form template to a new location, there are a number of items within the form template component files that need to be changed, such as the publishUrl in the manifest.xsf file. While you could do this within the InfoPath design mode, it is often more convenient and safer to use a script to modify these properties. In general, the following list represents the most common items that you may need to change:

  • The publishUrl

  • The wsdlUrl and serviceUrl of the Web service adapters

  • Database connection strings and other Data Connection parameters

  • The caption for the name of the form template

  • The form template URN

It is not necessary to modify all of these attributes for every form template deployment. In most cases, the script used to deploy a particular form template contains specific information about the form template itself, and where it is deployed.

Modification of the Processing Instructions (PI) in the template.xml file, which represents the default data for the form template, may also be necessary to avoid the conflict resolution dialog box when opening forms of the same name and version. This article does not address this specific issue, but the script could be modified to open this file and update the PI. For example code that provides a similar operation, refer to the SolutionFileModify, SolutionFileModifyVersion, and SolutionVersionUpdate functions in the xdown.js script code. This code file is used for the Downlevel Tool and can be found at Using the Downlevel Tool.

The XsnFixup.js script contains 10 functions that enable you to unpackage a form template (.xsn) file, modify the manifest.xsf file, repackage the form template, and save it to a new location. The full script is included at the end of the article. Copy and paste this code into a script editor or Notepad, and save it as xsnfixup.js.

The Microsoft Cabinet Software Development Kit (SDK) files and folders should be present in the same location where you save the script file, namely, in a containing folder called "CabSDK".

To use the script as-is, call it from a command line or batch file with the following syntax.

Signature

XsnFixup.js input.xsn output.xsn XPathToModify NewValue

Example

XsnFixup.js in.xsn out.xsn "/xsf:xDocumentClass/@publishUrl" "http://www.example.com/example.xsn"

Parameters

input.xsn

The source form template name and current location.

output.xsn

The destination form template name and location.

XPathToModify

The XPath of the element or attribute whose value needs to be updated.

NewValue

The new value of the element or attribute

Requirements

XsnFixup JScript Main Function

What follows is the main function of the XsnFixup.js code. As written, it enables you to modify a single attribute, such as the publishUrl. It accepts four parameters. Here is an example syntax for changing the publishUrl using a UNC path for the input and output locations.

xsnfixup \\server1\d$\test\test.xsn \\server2\e$\public\expenses.xsn
"/xsf:xDocumentClass/@publishUrl" "http://server2/expense/expenses.xsn"

To extend this script, you may want to eliminate the third and fourth arguments of the main function and hard-code the changes in the FixupXSF function.

function main( arguments )
{
    if( arguments.length != 4 )
    {
        WScript.Echo( 
            "Usage:\n\tXsnFixup.js input.xsn output.xsn XPathToModify NewValue\n" +
            "\n" + 
            "Example:\n\tXsnFixup.js in.xsn out.xsn \"/xsf:xDocumentClass/@publishUrl\" \"http://www.example.com/example.xsn\""
        );
        WScript.Quit();
    }

    FixupXSN( arguments(0), arguments(1), arguments(2), arguments(3) );
}
main( WScript.Arguments );

FixupXSF Function

The FixupXSF function is called from the FixupXSN function, immediately following the extraction of the form template component files from the XSN.

If you modify the main function to eliminate the third and fourth arguments, it is necessary to eliminate the arguments from this function as well as from where this function is called, in the FixupXSN function.

function FixupXSF( xsfInputPath, xsfOutputPath, xpath, newvalue )
{
    var fso = new ActiveXObject ("Scripting.FileSystemObject");

    var xsfDom = new ActiveXObject("MSXML2.DOMDocument.5.0");
    xsfDom.async = false;
    xsfDom.validateOnParse = false; // Ignore xsi:nil errors
    xsfDom.load( xsfInputPath );
    xsfDom.setProperty( "SelectionNamespaces", "xmlns:xsf='" + XsfNamespace + "'" );

    ModifyAttribute( xsfDom, xpath, newvalue ); 
 
    if( fso.FileExists( xsfOutputPath ) )
    {
        fso.DeleteFile( xsfOutputPath, true );      
    }

    xsfDom.save( xsfOutputPath );
}

If you need a script to modify multiple attributes, comment out the ModifyAttribute( xsfDom, xpath, newvalue ); statement and hard-code the necessary attribute modifications using new ModifyAttribute function calls. An example of changing the form template name would be as follows.

// Change form name to final deployed name
// (appears in Fill Out a Form dialog box and titlebar)
    ModifyAttribute( xsfDom, "/xsf:xDocumentClass/xsf:fileNew/xsf:initialXmlDocument/@caption",
"Your new form template name" ); 

Here's an example of how you would modify the wsdlUrl and serviceUrl of a Web service adapter data connection called "GetHoursWorked":

// Change Web Service calls to point to final deployment server
    ModifyAttribute( xsfDom,
"/xsf:xDocumentClass/xsf:dataObjects/xsf:dataObject
[@name='GetHoursWorked']/xsf:query/xsf:webServiceAdapter/@wsdlUrl",
"http://MyServer/webservices/timecard.asmx?WSDL"); 
    ModifyAttribute( xsfDom, "/xsf:xDocumentClass/xsf:dataObjects/xsf:dataObject
[@name='GetHoursWorked']/xsf:query/xsf:webServiceAdapter/xsf:operation/@serviceUrl",
"http://MyServer/webservices/timecard.asmx" );

This example points the form template to a new Web service location. In this case, the server "MyServer" contains a Web service called "timecard" which returns, among other data, the number of hours worked. The "GetHoursWorked" Web service adapter data connection corresponds to the name for this connection that is listed in the Data Connections dialog box in the InfoPath design mode.

Other Functions in the XsnFixup JScript Code

There are eight other functions that constitute the XsnFixup JScript code. In most cases, these functions do not need to be modified.

  • ExtractFilesFromXSN

  • CreateXSNFromFiles

  • ModifyAttribute

  • FixupXSN

  • PathCombine

  • QuoteString

  • ShellExecute

  • SaveToFile

Additional Considerations

If you are digitally signing the form template prior to deployment to a production environment, the digital signature should be the last step in the deployment process. Modifying any of the attributes of the form template after it has been signed will invalidate the digital signature.

If you need to deploy a form template to multiple locations, such as two different test environments, create two script files with specific information for each server, and then use a batch (.bat) file that invokes multiple script files in succession.

Full XsnFixup.js Code

Included here is the full code that can be copied into a text editor and saved as XsnFixup.js.

// InfoPath form template extraction and creation script for
// modification of a single XPath value in the manifest.xsf

var g_CabSdkBin = ".\\CabSdk\\bin";
var g_ExtractExe = PathCombine( g_CabSdkBin, "extract.exe" );
var g_MakecabExe = PathCombine( g_CabSdkBin, "makecab.exe" );
var g_XsfNamespace = "http://schemas.microsoft.com/office/infopath/2003/solutionDefinition";
var g_GetSpecialFolder_TemporaryFolder = 2;

// Helper functions 
 
function PathCombine( dir, file )
{
    return dir + "\\" + file ;
}
 
function QuoteString( string )
{
    return ( "\"" + string + "\"" );
}
 
function ShellExecute( string, flagWait )
{
    if( flagWait == null )
      flagWait = true;
    var WScriptShell = WScript.CreateObject( "WScript.Shell" );
    return WScriptShell.Run( string, 0, flagWait );
}

// Called from CreateXSNFromFiles, writes final XSN to filePath

function SaveToFile( data, filePath )
{
    var fso = new ActiveXObject( "Scripting.FileSystemObject" );
    fso.CreateTextFile( filePath, true );
    var TextStream = fso.OpenTextFile( filePath, 2 );
    TextStream.Write( data );
    TextStream.Close(  );
}

// Called from FixupXSN, extracts files from XSN cab

function ExtractFilesFromXSN( xsnInputPath, outputFolder )
{
    var Parameters;
 
    // "/Y" prevents prompting before overwriting
    // "/E" extract all files
    // "/L" location to extract to
    
    if( outputFolder != null )
        Parameters = "/Y /E /L " + QuoteString( outputFolder );
 
    ShellExecute( QuoteString( g_ExtractExe ) 
        + " " + Parameters
        + " " + QuoteString( xsnInputPath ), true );
} 

// Called from FixupXSN, creates XSN cab from source files

function CreateXSNFromFiles( inputFolder, xsfName, xsnOutputPath )
{
    var fso = new ActiveXObject ("Scripting.FileSystemObject");
    var tempName   = fso.GetTempName();
    var tempFolder = fso.GetSpecialFolder(g_GetSpecialFolder_TemporaryFolder);
    var tempPath   = PathCombine( tempFolder, tempName );

    var ddfString = "";
    ddfString += ".Set DiskDirectoryTemplate='"+ tempFolder +"'\r\n";
    ddfString += ".Set CabinetNameTemplate='" + tempName + "'\r\n";
 
    var xsfDom = new ActiveXObject( "MSXML2.DOMDocument.5.0" );
    xsfDom.async=false;
    xsfDom.validateOnParse=false; // for ignoring xsi:nil errors..
    xsfDom.load( PathCombine( inputFolder, xsfName ) );
    xsfDom.setProperty( "SelectionNamespaces", "xmlns:xsf='" + g_XsfNamespace + "'" );
 
    ddfString += QuoteString( PathCombine( inputFolder, xsfName ) ) + "\r\n";
    var fileNodes = xsfDom.selectNodes( "//xsf:files/xsf:file/@name" );
    for( var i = 0; i < fileNodes.length; i++ )
    {
        ddfString += QuoteString( PathCombine( inputFolder, fileNodes( i ).text ) ) + "\r\n";
    }
 
    var ddfPath = PathCombine( tempFolder, "makecab.ddf" );
    SaveToFile( ddfString, ddfPath );
    ShellExecute( QuoteString( g_MakecabExe ) + " /v1 /f " + QuoteString( ddfPath ), true );
    fso.DeleteFile( ddfPath );

    // Move the XSN to its new home
    if( fso.FileExists( xsnOutputPath ) )
    {
        fso.DeleteFile( xsnOutputPath, true );      
    }
    fso.MoveFile( tempPath, xsnOutputPath );

    // Delete setup files output into current directory by CAB process
    var oScratchFiles = new Array( "setup.inf", "setup.rpt" );
    for( var i in oScratchFiles )
    {
        var strScratchFile = oScratchFiles[i];
        if( fso.FileExists( strScratchFile ) )
        {
            fso.DeleteFile( strScratchFile, true );      
        }
    }
}

// Called from FixupXSF, modifies value of specified XPath

function ModifyAttribute( dom, xpath, value )
{
    var attributeList = dom.selectNodes( xpath );

    for(;;)
    {
        var attribute = attributeList.nextNode();

        if( attribute == null )
            break;

        WScript.Echo( "Replace:\t" + attribute.nodeValue + "\nWith:\t" + value );

        attribute.nodeValue = value;  
    }
}

// Called from FixupXSN, creates DOM, loads XSF, and invokes
// ModifyAttribute to change specified XPath to new value

function FixupXSF( xsfInputPath, xsfOutputPath, xpath, newvalue )
{
    var fso = new ActiveXObject ("Scripting.FileSystemObject");

    var xsfDom = new ActiveXObject("MSXML2.DOMDocument.5.0");
    xsfDom.async = false;
    xsfDom.validateOnParse = false; // Ignore xsi:nil errors
    xsfDom.load( xsfInputPath );
    xsfDom.setProperty( "SelectionNamespaces", "xmlns:xsf='" + g_XsfNamespace + "'" );

    ModifyAttribute( xsfDom, xpath, newvalue ); 
 
    if( fso.FileExists( xsfOutputPath ) )
    {
        fso.DeleteFile( xsfOutputPath, true );      
    }

    xsfDom.save( xsfOutputPath );
}

// Called from Main, invokes three other functions to extract,
// modify, and repackage XSN

function FixupXSN( xsnInputPath, xsnOutputPath, xpath, newvalue )
{
    var fso = new ActiveXObject( "Scripting.FileSystemObject" );
   
    if( ! fso.FileExists( xsnInputPath ) )
    {
        WScript.Echo( "File does not exist: " + xsnInputPath );
        WScript.Quit();
    }

    // Create temporary folder and explode the XSN
    var tempFolderPath = fso.CreateFolder( PathCombine( fso.GetSpecialFolder(g_GetSpecialFolder_TemporaryFolder),
fso.GetTempName() ) ).Path;
    ExtractFilesFromXSN( xsnInputPath, tempFolderPath );

    // Modify the XSF in place    
    var xsfPath = PathCombine( tempFolderPath, "manifest.xsf" );
    FixupXSF( xsfPath, xsfPath, xpath, newvalue );

    // Generate the new XSN
    CreateXSNFromFiles( tempFolderPath, "manifest.xsf", xsnOutputPath );

    // Cleanup
    var tempFolderPath = fso.DeleteFolder( tempFolderPath );
}

// Main function to accept source and destination XSN locations,
// a single XPath to modify, and the new value

function main( arguments )
{
    if( arguments.length != 4 )
    {
        WScript.Echo( 
            "Usage:\n\tXsnFixup.js input.xsn output.xsn XPathToModify NewValue\n" +
            "\n" + 
            "Example:\n\tXsnFixup.js in.xsn out.xsn \"/xsf:xDocumentClass/@publishUrl\" \"http://www.example.com/example.xsn\""
        );
        WScript.Quit();
    }

    FixupXSN( arguments(0), arguments(1), arguments(2), arguments(3) );
}

main( WScript.Arguments );

When you are deploying a form template to a new location, such as from a test server to a production server, it is best to automate the process with a script.

Show: