Execute Custom Script with ArcScript
Arc includes a fully featured scripting language called ArcScript which allows developers to extend the application’s feature set by enabling the execution of custom logic. The application exposes three contexts in which ArcScript can be implemented:
- A Dedicated Script Connector: Performs arbitrary logic as part of a connected workflow, with optional file-based input and output.
- Event Scripting: Allows scripts to be triggered by the event callbacks exposed by each connector, e.g. sending or receiving a file.
- Data Mapping: Allows scripts to enhance the process of transforming data between formats within an XML Map Connector.
This page provides an overview of ArcScript, as well as specific examples of tasks that can be accomplished by employing it within the above contexts. This resource is intended to demonstrate the flexibility of ArcScript and to help get developers started with writing their own custom scripts.
Table of Contents
Scripting Overview
This section serves as an introduction to ArcScript for developers who are already familiar with scripting concepts, but who may not have extensive experience with ArcScript specifically. After becoming familiar with ArcScript concepts, the Scripting section of the documentation should be used as a reference for ArcScript’s keywords, operations, and formatters.
ArcScript as XML
ArcScript is an XML-based language. All ArcScript statements are XML elements whose names contain two parts:
- The element namespace, arc (earlier versions used rsb or api as the namespace; these are still supported for backward compatibility).
- An element name, which is an ArcScript keyword like set, call, or if.
For example:
<arc:call op="myOperation">
ArcScript statements use XML attributes to define their parameters, e.g. the op attribute in the above arc:call statement indicates the operation to invoke. As another example of providing an XML attribute to an ArcScript statement, the following statement uses the in XML attribute:
<arc:call op="myOperation" in="inputItem">
This XML attribute is used to pass an input item to the operation (items are discussed in the Attributes and Items section).
The remaining concepts in this section build upon the syntactical principle: ArcScript uses keywords in XML elements to define operations and XML attributes within those operations to provide their arguments.
Attributes and Items
The word ‘attribute’ is used in two different ways when discussing ArcScript. The first usage has already been described in the previous section: ArcScript keywords are specified in XML elements, and the XML attributes of these elements provide context to the keyword behavior. The second usage of the word ‘attribute’ is described in the following section.
To distinguish between the two uses, the phrase ‘XML attributes’ is always used explicitly to refer to XML attributes. Any other discussion of ‘attributes’ (without the ‘XML’ modifier) implicitly refers to the usage described below.
Attributes
Attributes, often shortened to attrs, are used by ArcScript to declare variables. These variables are set using the arc:set keyword; the name of the attr is set using the attr XML attribute and the value of the attr is set using the value XML attribute.
For example, the ArcScript syntax to set: myVariable = 5 is:
<arc:set attr="myVariable" value="5" />
For longer attribute values, the value can be specified as the content of the arc:set element rather than via the ‘value’ XML attribute:
<arc:set attr="myLongAttr">This attribute needs to be set to multiple lines of text.Here is another line of text.The newline characters in these lines of text will be included in this attribute value.</arc:set>
To access the value stored by an attr, surround the name of the attr in square brackets like so: [myVariable].
For example, the following line sets a new variable to the same value as the variable set in the previous example:<arc:set attr="anotherVariable" value="[myVariable]" />
These square-bracketed attr names can be interspersed with string literals, like the following:
<arc:set attr="myEquation" value="[myVariable] plus [myVariable] equals 10" />
Attrs are loosely typed, and keywords or formatters that require numerical input will attempt to resolve attrs as numbers. Otherwise, attrs are treated as strings.
ArcScript attrs do not need to be declared prior to setting a value; the arc:set statement both initializes and sets the variable.
attrs are defined within a scope: if an attr is initialized inside of an if statement, the attr will not be available outside of the if (i.e. after the arc:if element is closed).
Items
Items are collections of attrs. You can think of them as objects with fields and no functions (e.g. records). In practice, items are typically used like prefixes to attribute names. Attributes that belong to an item are referenced using the syntax:
itemName.attrName
The arc:set keyword can be used to set an attribute within an item:
<arc:set attr="myItem.someVar" value="Hello World" />
Items are sometimes set directly without using an attribute name, in which case the item XML attribute is used instead of the attr XML attribute:
<arc:set item="myItem" />
This syntax is helpful for initializing an item in a particular scope to ensure that the item contents are available later in the script, within that scope.
Items are useful for grouping variables together, and these grouped variables can then be passed as a set to the input or output of an operation. For example, the httpPost operation requires a url and postdata as input. These values can be set as attrs of an item, then that item can be passed in as input to the operation:
<arc:set attr="httpItem.url" value="https://arc.cdata.com" />
<arc:set attr="httpItem.postdata" value="Greetings from within an ArcScript example" />
<arc:call op="httpPost" in="httpItem" />
Operations generate Items as output.
Take for example the httpGet operation, which returns web content as output. In the <arc:call> statement for this operation, an output item should be specified using the out attribute. All output data, like the HTTP content, is returned as attributes of this output item. The name of each output attribute is defined specifically for each operation (see the Scripting section of the documentation for specifications of output attribute names).
The attrs of an output item are available within the scope of the operation call (i.e. until the XML element with the arc:call statement is closed), so these values often need to be set on an item with a more global scope.
In the following example, the httpItem item serves two functions: (1) it is an input item with the url parameter set for the httpGet operation, and (2) it has a global scope, so the response from the httpGet can be set as an attr of this item to use outside of the operation call. The outItem is used as an output item for the httpGet call. The output attributes for an operation must be known ahead of time in order to access output data. In the case of httpGet, the name of the output attribute for the web page contents is http:content. Since outItem is the output item and http:content is the output attribute, the web page contents are accessed by referencing [outItem.http:content], and the data from this attr is used to set an attr of the global item (httpItem) for later use:
<arc:set attr="httpItem.url" value="https://arc.cdata.com" />
<arc:call op="httpGet" in="httpItem" out="outItem">
<arc:set attr="httpItem.response" value="[outItem.http:content]" />
</arc:call>
In the above example, the [outItem.http:content] syntax comes from the fact that http:content is defined as an output attribute of the httpGet operation. So the output item can be set arbitrarily through the out parameter, but the attributes of this item are determined by the operation itself.
Items are used to push output from a script. For example, the output from a Script Connector requires two output attributes, filename (the name of the file that will be pushed out) and data (the contents of the output file). The arc:push statement is used to push out an item that has these two attributes defined. For example:
<!-- set attributes of an http item for calling httpGet -->
<arc:set attr="httpItem.url" value="https://arc.cdata.com" />
<!-- initialize an item that will eventually be pushed out as an output file -->
<arc:set attr="pushItem.filename" value="myOutputFile.txt" />
<!-- call the http GET and store the response as the push item 'data' (the contents of the output file) -->
<arc:call op="httpGet" in="httpItem" out="outItem">
<arc:set attr="pushItem.data" value="[outItem.http:content]" />
</arc:call>
<!-- push out the output file -->
<arc:push item="pushItem" />
Executing the above script in a Script Connector would cause the connector to output a file that contains the Arc website homepage HTML.
Formatters
Attributes in ArcScript are manipulated using Formatters. Attributes are “piped in” to Formatters using the vertical pipe character ‘|’ and the full expression is contained within square brackets. Formatters can be chained together from left-to right using the ‘|’ character.
String Formatters
String Formatters transform and gather information from string values. The value of the attribute “piped in” to the Formatter is the input to the Formatter (i.e. the Formatter processes the value within the attribute on the left):
<arc:set attr="myAttr" value="some basic string" />
<arc:set attr="stringLength" value="[myAttr | getlength()]" />
An example of Chaining formatters from left to right:
<arc:set attr="myAttr" value="some basic string" />
<arc:set attr="upperCaseString" value="[myAttr | replace('basic', 'uppercase') | toupper()]" />
Other common String Formatters are:
- substring(startIndex, length)
- base64encode()
- equals(‘target string’)
- split(delimiter, index)
Math Formatters
In addition to String Formatters, Math Formatters can be used to perform mathematical operations on data:
<arc:set attr="inputNum" value="5" />
<arc:set attr="outputNum" value="[rawNum | multiply(2) | add(4)]" />
<arc:set attr="myBool" value="[outputNum | equals(14)]" />
In the above example, outputNum resolves to 14, and myBool resolves to ‘true’. Double ampersand (&&) and double vertical pipe (||) can be used as boolean ‘and’ and ‘or’ respectively:
<arc:set attr="inputNum" value="5" />
<arc:set attr="makeMeFalse" value="[inputNum | greaterthan(4)] && [inputNum | lessthan(3)]" />
In the above example, makeMeFalse would in fact resolve to ‘false’.
The full list of ArcScript formatters can be found in the Formatters documentation section.
Conditional Logic
The arc:if keyword is the basis of conditional logic in ArcScript. This statement requires an exp attribute set to the boolean expression representing the condition:
<arc:set attr="myGreeting" value="Hello World" />
<arc:if exp="[myGreeting | contains('Hello')]">
<arc:set attr="myFarewell" value="[myGreeting | replace('Hello', 'Goodbye')]" />
</arc:if>
The arc:else keyword is often paired with arc:if. Importantly, the else appears inside of the if statement, like this:
<arc:set attr="myString" value="Paddleboarding is fun">
<arc:if exp="[myString | contains('!')]">
<arc:set attr="myExclamation" value="[myString]" />
<arc:else>
<arc:set attr="myExclamation" value="[myString]!!" />
</arc:else>
</arc:if>
ArcScript also supports arc:select, arc:equals, arc:check, arc:null, and arc:notnull statments for conditional logic. Please see the ArcScript documentation for the specific syntax used in each of these statements.
Operations
Operations in ArcScript provide functionality more advanced than single keywords or Formatters. These are functions that may require input (in the form of attributes set on an input item) and provide output (in the form of attributes set on an output item). Common operations include:
- fileRead: Open a file and make its contents available in script.
- fileMove: Rename a file.
- httpGet or httpPost, httpPut, etc: Send HTTP requests to a remote web server.
- dbQuery: Provide a database connection string and query to return database results.
- xmlDOMSearch: Loop over an XML document at a specified xpath.
- sysExecute: Call an external script or program.
A full list of supported Operations is found here: Arc Operations.
Operations are always invoked using the arc:call statement:
<arc:set attr="myFile.file" value="C:\\temp\\somefile.txt" />
<arc:call op="fileRead" in="myFile" out="tempOut">
<arc:set attr="myFile.contents" value="[tempOut.file:data]" />
</arc:call>
The Input and Output XML Attributes of operations were discussed in the Attributes and Items section of this article.
Lists and Arrays
Attributes in ArcScript can be defined as lists by using the pound sign (#) at the end of the attribute name:
<arc:set attr="students.names#" value="Tom Jones" />
For list attributes, using the arc:set keyword does not overwrite the current value(s) in the attribute, but adds a new value to the end of the list. For example, the following script adds three names to the list of students:
<arc:set attr="students.names#" value="Tom Jones" />
<arc:set attr="students.names#" value="Cindy Longo" />
<arc:set attr="students.names#" value="Mabel Spinner" />
Once a list is set, the values can be referenced directly with an index:
<!-- my favorite student is Mabel Spinner -->
<arc:set attr="favoriteStudent" value="[students.names#3]" />
Note that the list is 1-indexed, so students.names#3 resolves to ‘Mabel Spinner.’
The arc:enum keyword is useful for enumerating all values of a list. Inside an arc:enum call (where attr is a list attribute and expand is set to true), the reserved [_value] attr can be used to reference each value in the list in turn. The index of the current value is available via [_index]. For example, the following script outputs all of the names from students.names in an index-delimited line:
<arc:set attr="outitem.filename" value="names.txt" />
<arc:set attr="outitem.data" value="" />
<arc:enum attr="students.names" expand="true">
<arc:set attr="outitem.data" value="[outitem.data] [_index]) [_value]">
</arc:enum>
At the end of execution, the outitem.data attribute would contain this string:
1) Tom Jones 2) Cindy Longo 3) Mabel Spinner
All arrays in ArcScript are treated as lists, so there is no separate syntax for a list of static size. The same arc:enum keyword should be used to enumerate over all collections of attribute values.
Working with XML
Arc uses XML as a common data format, and ArcScript is often used to interact with XML documents. This section explicates the following concepts for manipulating XML in ArcScript:
- The xmlDOMSearch operation is used to load XML documents and loop through them.
- The xpath formatter is used to access specific values within an XML document (i.e. inside an xmlDOMSearch call).
xmlDOMSearch
The xmlDOMSearch operation is used to load an XML document (e.g. parse the XML Document Object Model) and loop over a specified xpath. Take the following simple XML as an example:
<Items>
<Name>
<First>Chris</First>
<Last>Bosh</Last>
</Name>
<Name>
<First>Dwyane</First>
<Last>Wade</Last>
</Name>
</Items>
Now imagine xmlDOMSearch is called with the xpath input attribute set to /Items/Name:
<arc:set attr="xmlItem.xpath" value="/Items/Name" />
<arc:call op="xmlDOMSearch" in="xmlItem">
<!-- do something -->
</arc:call>
Any script within the xmlDOMSearch call (i.e. where the XML comment is) would execute twice; once when the xmlDOMSearch loops over the ‘Name’ element for Chris Bosh, and again when the xmlDOMSearch loops over the ‘Name’ element for Dwyane Wade. If more XML elements existed at the /Items/name xpath, the operation would continue looping through each such element.
The first time xmlDOMSearch is called on an XML file, the uri input attribute should be set to the XML file to load. Often, this operation is called within a dedicated Script Connector and the XML file to load is the current file being processed by the connector (e.g. the target XML file is uploaded as an input file to the Script Connector). In this case, the [FilePath] attribute resolves to the current file URI, so the following code can be used to load the document:
<arc:set attr="xmlItem.uri" value="[FilePath]" />
<arc:set attr="xmlItem.xpath" value="/Items/Name" />
<arc:call op="xmlDOMSearch" in="xmlItem">
<!-- do something -->
</arc:call>
If the XML file to parse is not the current file being processed by a Script Connector, the URI should instead be set to the filepath of the target XML file.
xpath
Within an xmlDOMSearch call, the xpath formatter can access XML values within the current loop. Let's revisit the example XML snippet from the previous section and extract the first and last names of Chris Bosh and Dwyane Wade:
<arc:set attr="xmlItem.uri" value="[FilePath]" />
<arc:set attr="xmlItem.xpath" value="/Items/Name" />
<arc:set item="players" />
<arc:call op="xmlDOMSearch" in="xmlItem">
<arc:set attr="players.name#" value="[xpath('First')] [xpath('Last')]" />
</arc:call>
Note the [xpath(‘First’)]/[xpath(‘Last’)] syntax, which is used to extract the values from Items/Names/First and Items/Names/Last respectively. Note that the xpath provided to the xpath() formatter is relative to the xpath provided to the xmlDOMSearch operation.
Script Connector
The Script Connector provides the most flexible context for writing custom logic in ArcScript. Script Connectors follow the same pattern as other connectors: Input files are read from the Input/Send Folder, and any output generated by the script is pushed to the Output/Receive Folder. Script Connectors do not need to have input files, nor do they need to generate output.
The example in this section will both read from an input file and create an output file.
Script Connector Input
When the Script Connector processes a file, the path to this file is accessible as the reserved FilePath input attribute. This value can be used in conjunction with operations like fileRead or xmlDOMSearch to load the contents of the input file.
For example, the following snippet assumes the input file is a text file that needs to be loaded into the script:
<arc:set attr="fileItem.file" value="[FilePath]" />
<arc:call op="fileRead" in="fileItem" out="outItem">
<arc:set attr="fileItem.contents" value="[outItem.file:data]" />
</arc:call>
The use of [FilePath] does not need to be preceeded by defining this attribute because it is a pre-defined input attribute for the Script Connector. If the above script were to run without an input file (e.g. if the Receive button were clicked in the Output tab to execute the script without providing any input) then an error would occur during the fileRead operation.
Script Connector Output
The arc:push keyword is used to generate an output file via a Script Connector. The Script Connector has two required output attributes that must be set prior to the arc:push call: filename (the name of the output file) and data the contents of the output file). These two attributes should be set on an item, and that item should be included in the arc:push statement, like the following:
<arc:set attr="pushItem.filename" value="myOutputFile.txt" />
<arc:set attr="pushItem.data" value="Some contents for my output file" />
<arc:push item="pushItem" />
Headers/metadata can be added to the output file by using the defined header: output attribute. Each attribute of the output item that begins with header: will be treated as a new custom header (the “header:” will not be included in the resulting header name). For example, the following snippet adds two headers to the output file:
<arc:set attr="pushItem.filename" value="myOutputFile.txt" />
<arc:set attr="pushItem.data" value="Some contents for my output file" />
<arc:set attr="pushItem.header:myCustomHeader" value="A value for my header" />
<arc:set attr="pushItem.header:Content-Type" value="text/plain" />
<arc:push item="pushItem" />
Event Scripting
Connectors in an Arc Flow have Events that can trigger custom script execution. The Before Send Event fires after a Connector has finished preparing a message to be processed but before performing the processing (note that the contents of the message cannot be altered at this point). The After Receive Event fires after a connector has either processed a file locally (e.g. an EDIFACT Connector translating a local EDI file to XML) or received/downloaded a file from a remote party (e.g. receiving an incoming AS4 file).
In general, scripts that alter the contents of a message/file, including adding headers to that message, should be separated out into a dedicated Script Connector. Scripts inside Events should be restricted to sending alerts, copying or moving the file based on custom logic, and other operations that do not require manipulating the message contents.
Event scripts will not raise errors in the way that dedicated Script Connector scripts will. If a connector successfully sends or receives a message, the transaction is considered successful — even if it triggers an event script that encounters an error. For this reason, error-sensitive scripts should be written in a dedicated Script Connector.
Event Input
Event scripts always have a defined set of input attributes that are available as variables in the script:
- [FilePath] - The full path and filename of the file sent/processed/received by the connector.
- [FileName] - The filename of the file sent/processed/received by the connector.
- [Direction] - Whether the event fired during ‘Sending’ or ‘Receiving.’
- [ConnectorId] - The name of the connector where the event fired.
- [MessageId] - The unique ID that identifies the message throughout the flow (regardless of the filename).
Referencing an input attribute in the event script follows the same syntax as referencing any defined attribute/variable in ArcScript. The following example might be placed in the After Receive event to copy the file after receiving:
<arc:set attr="moveItem.Source" value="[FilePath]" />
<arc:set attr="moveItem.Destination" value="C:\\some\\path\\[FileName]" />
<arc:call op="fileCopy" in="moveItem" />
Some connectors will have additional event input attributes that are specific to the protocol or use case associated with that connector, for example:
- [AS2MessageId] — The Message ID value at the AS2 protocol level (rather than Arc’s internal tracking of messages)
- [TemplateName#] — In Database Connectors (and other backend connectors), events fire after an Input or Output template is executed, and this contains the template name
Event Output
Event scripts do not have output attributes, since they should not be used to alter the contents of the message processed by the connector. Scripts that interact with the headers or body of a message should be written in dedicated Script Connectors to gain access to variable output.
Data Mapping Scripting
ArcScript can be useful for sophisticated mapping logic. All mapping occurs in the XML Map Connector, and users who are unfamiliar with the XML Map Connector are strongly encouraged to review the dedicated connector documentation to help understand this section. Each output node in the XML Map visual designer has the option to insert a ‘Code Script’ mapping via the </> icon.
Note that most mapping cases will not require custom scripting, as the basic drag-and-drop mapping and Expression Editor cover the vast majority of data transformation and manipulation cases. The ‘Code Script’ interface is provided for mapping scenarios where custom logic must be implemented, such as setting or calculating a variable value early in the mapping, then referencing that variable as output later in the mapping.
Result.Text and Script Nodes
When an output node is set to a custom script, the result.text attribute determines which value will be written to the output file during the mapping. In other words, result.text is the single output attribute of the script.
Some scripts do not need an output attribute. For example, a script may simply calculate a value that is used later in the mapping, without needing to output that value right now. These scripts should not be written as a ‘Code Script’ for an output node, and instead should be written in a Script Node. Script Nodes can be added to the Destination mapping by right-clicking a node in the Destination panel and selecting ‘New Script.’ Script Nodes have no result.text and do not appear in the XML output.
_map
The _map item is critical for mappings where a value must be calculated early in the mapping and referenced later in the mapping. This item behaves like any other ArcScript item, except its scope is the entire document mapping; in other words, the attributes of this item are not cleared until the entire document has been mapped. Other items will be cleared/recycled each time the mapping moves on to the next output node.
To help understand the _map item, consider a common use case: calculating the number of line items when mapping an outbound Purchase Order or Invoice. As background, generating an X12 810 (Invoice) requires looping over the line item data to generate IT1Loop1 segments, then later in the mapping, the CTT segment needs to include the total number of line items in the document. However, once the mapping has reached the CTT segment it has already exited the IT1Loop1 loop, so the number of line items needs to be ‘stored’ within _map when looping through IT1Loop1’s and referenced when mapping the CTT segment.
For this use case, a Script Node should be added within the Foreach Loop that generates IT1Loop1 structures, with script like the following:
<arc:set attr="_map.lineItemCount" value="[_map.lineItemCount | def(0) | add(1)]" />
This line increments the lineItemCount attribute of the _map item, and if this attribute does not yet exist, it defaults the value to 0 (before incrementing).
Later in the mapping, when generating the CTT segment, the CTT01 node should be set to ‘Code Script’ and the script can return the value calculated earlier:
<arc:set attr="result.text">[_map.lineItemCount]</arc:set>
This same approach for setting attributes of _map and referencing them in later scripts is the same for use cases that do not necessarily involve counting loops.
Ready to get started?
Use Arc's free 30-day trial to start building your own custom workflows today: