> ## Documentation Index
> Fetch the complete documentation index at: https://docs.kasoftware.com/llms.txt
> Use this file to discover all available pages before exploring further.

# ArcScript 簡介

> ArcScript 語言的核心概念，包括物件、物件集、運算器、關鍵字和內建指令碼物件，並提供範例指令碼。

export const siteNameShort = "知行之橋";

export const siteName = "知行之橋";

ArcScript 是 {siteName} 中內建的一種基於 XML 的語言，可用於編寫自定義處理邏輯。ArcScript 可以輕鬆轉換檔案或訊息，並與其它業務流程整合。{siteNameShort} 包含完整的[範例指令碼](#範例指令碼)，用於傳送電子郵件、執行批次處理檔案、處理檔案等。您可以從管理控制檯將這些範例插入到指令碼和事件中。

不過，ArcScript 也是一種高階程式語言，能夠控制資料存取和處理的幾乎每一個方面。您可以使用[關鍵字](./keyword-reference/keywords)、屬性、物件、[運算器](./operations/operations)和物件集來編寫指令碼，並在所有端口的[事件](./scripting#event-scripting)、專用 [Script](../connectors/script) 和 [REST](../connectors/rest) 端口，以及 [XML Map 端口](../connectors/xml-map/xml-map)的[自定義指令碼](../connectors/xml-map/xml-map-advanced#custom-scripts)選項中使用這些指令碼。

* **屬性**：名稱-值對中的名稱部分，例如 attribute="address"、value="123 Pleasant Lane"。
  * 使用 `#` 字元表示屬性是陣列。這表示陣列可以包含多個值，每個值都可以使用從 1 開始的索引來引用。
  * 例如，`[myitem.myattribute#2]` 指向 `myattribute` 屬性的第二個值。

* **物件**：描述輸入或輸出的一組相關屬性-值對。例如：

  ```
  Attribute="name" value="Bob"
  Attribute="address" value="123 Pleasant Lane"
  Attribute="phone" value="123-4567"
  ```

* **物件集**：物件的清單，例如包含客戶地址和電話號碼的客戶清單。

* **運算器**：接受物件作為輸入並生成物件集作為輸出的方法的通用名稱。

* **關鍵字**：ArcScript 語句，例如 [arc:set](./keyword-reference/op-arc-set)。

<Note>ArcScript 中的陣列限制為 32768 個成員。</Note>

ArcScript 包含許多關鍵字，可用於執行以下操作：

* 描述指令碼輸入和輸出
* 使用 if/else 語句和 case 語句等高階程式設計結構控制執行流程
* 呼叫運算器並定義自己的運算器
* 建立和修改用作運算器輸入的物件，以及物件集（運算器的輸出）
* 透過迭代物件集中的物件來處理運算器呼叫產生的物件集

## 範例指令碼

{siteNameShort} 包含用於自動化常見操作（如傳送電子郵件）的完整程式碼片段。在 [Script 端口的設定索引標籤](../connectors/script#settings-tab)或任意端口的**事件**索引標籤上，單擊**插入片段**，然後選擇要執行的操作。必要的程式碼會插入到游標處。

以下部分介紹如何使用和擴充套件這些程式碼片段來編寫自定義處理邏輯。

### 使用事件輸入

每個事件都提供相關輸入，可將其用作運算器的輸入參數。輸入參數由 info 部分中的 input 屬性定義。

使用事件的預定義輸入可以處理已傳送或已接收的檔案，或傳送包含任何錯誤訊息的電子郵件。還可以使用其它輸入。例如，**After Receive** 事件的可用輸入如下：

```xml theme={null}
<arc:info title="After Receive" desc="This event is fired after receiving a file.">
  <input name="WorkspaceId"      desc="The id of the workspace that is receiving file." />
  <input name="ConnectorId"      desc="The id of the connector that is receiving file." />
  <input name="Direction"        desc="The direction of transaction." />
  <input name="Filename"         desc="The name of the file that was received." />
  <input name="FilePath"         desc="The path of the file that was received." />
  <input name="Attachment#"      desc="The path of the attachment was received." />
  <input name="MessageId"        desc="The Id of the transaction." />
  <input name="ErrorMessage"     desc="If an error occurred, this will contain the error message." />
</arc:info>
```

### 使用運算器

使用內含的程式碼範例可以呼叫一些內建[運算器](./operations/operations)。下面的範例使用 [appSendEmail](./operations/op-app-send-email) 運算器在收到檔案後傳送電子郵件。要使用它，只需替換佔位符值：

```xml theme={null}
<!-- Send Email -->
<arc:set attr="email.To"         value="Recipient(s)"/>
<arc:set attr="email.Subject"    value="Before Send"/>
<arc:set attr="email.Message"    value="File [Filename] was processed."/>
<arc:call op="appSendEmail"/>
```

<Note>僅當您此前已在**設定**（單擊齒輪圖示存取）中配置了郵件伺服器時，上面顯示的指令碼才有效。導航到[提醒索引標籤](../getting-started/administration/settings/alerts)的**電子郵件設定**部分。appSendEmail 運算器使用同一郵件伺服器。</Note>

### 擴充套件範例指令碼

使用內含的程式碼範例可以將預定義輸入傳遞給[運算器](./operations/operations)。您還可以傳入特定於運算器的輸入。例如，[appSendEmail](./operations/op-app-send-email) 運算器接受正文文字和附件等多個附加輸入。使用 [arc:set](./keyword-reference/op-arc-set) 關鍵字提供這些值。

使用 [arc:call](./keyword-reference/op-arc-call) 關鍵字可以呼叫事件中的任何內建運算器，或呼叫 API。

使用其它關鍵字可以控制執行流程等。ArcScript 在計算上是完備的，幷包含多種增強功能，旨在讓處理和自動化更簡單。有關 ArcScript 語法及其功能的更多資訊，請參閱[指令碼](./scripting)。

## ArcScript 中的物件

物件集由*物件*組成，但在 ArcScript 中，物件本身的用途遠不止作為物件集中的單個部分。它們還用於表示運算器的輸入。

### 宣告物件

為了提高可讀性並便於日後修改指令碼，知行軟體建議在 ArcScript 中建立顯式輸入物件，並在單獨的行中將其傳遞給運算器。物件透過 [arc:set](./keyword-reference/op-arc-set) 關鍵字建立、命名並賦予屬性值：

```xml theme={null}
<arc:set item="input" attr="mask" value="*.txt" />
```

上面的程式碼片段將名為 `input` 的物件上的 `mask` 屬性設定為值 `*.txt`。在這種情況下，輸入物件就像 ArcScript 中的變數。

不過，名為 `input` 的物件從未顯式宣告。相反，當您第一次嘗試為其設定屬性時，該物件就會被建立。在此範例中，如果輸入物件不存在，則會建立該物件並設定 mask 屬性。

<Tip>
  您也可以使用“簡寫”方法宣告物件和屬性。例如：

  ```xml theme={null}
  <arc:set attr="colors.myfavorite" value="green" />
  ```

  此程式碼片段建立一個 `colors` 物件，其 `myfavorite` 屬性的值為 `green`。
</Tip>

### 透過查詢字串參數傳遞物件

作為建立顯式輸入物件的替代方法，您可以透過 [arc:call](./keyword-reference/op-arc-call) 查詢字串參數的形式將輸入參數傳遞給運算器。為了說明顯式宣告物件與將物件作為參數傳遞之間的區別，請參考以下幾行：它們宣告一個名為 `file` 的物件，並將該物件傳遞給運算器以讀取一行內容：

```xml theme={null}
<arc:set attr="file.file" value="[filepath]" />

<arc:call op="fileReadLine" in="file">
```

要使用查詢字串參數完成同樣的操作，可以改用以下語法：

```xml theme={null}
<arc:call op="fileReadLine?file=[filePath | urlencode]">
```

<Note>使用此格式要求透過 `urlencode` 參數對參數進行 URL 編碼。這可確保應用程式正確解析檔名中的特殊字元或保留字元，而不會出錯。</Note>

### 選擇屬性值

要引用屬性，請使用 `item.attribute` 語法（例如 `input.mask`）。要查詢屬性值，請將屬性名放在方括號（\[ ]）中。這會告訴直譯器您要計算該字串，而不是將其解釋為字串文字。

例如，請參考以下程式碼片段：

```xml theme={null}
<arc:set item="item1" attr="attr1" value="value1"/>
<arc:set item="item1" attr="attr2" value="item1.attr1"/>
<arc:set item="item1" attr="attr3" value="[item1.attr1]"/>
```

結果如下：

* `item1.attr1` 被賦予文字字串值 `value1`。
* `item1.attr2` 被賦予文字字串值 `item1.attr1`。
* `item1.attr3` 被賦予值 `value1`，因為字串 `[item1.attr1]` 會在執行時被計算為 `item1` 的 `attr1` 屬性。

<Note>可以使用反斜槓逸出字元串文字中的方括號。</Note>

### 預設物件

在 ArcScript 的內部物件堆疊中，始終存在一個隱式、未命名的物件，即*預設物件*。雖然可以使用此物件編寫完整指令碼，但最佳實踐是根據需要定義自己的顯式輸入和輸出物件。這會讓指令碼更易讀，並降低覆蓋現有屬性的風險。對於簡單的指令碼場景，可以在以下兩種情況下使用預設物件，使指令碼稍短且更易編寫：

* 呼叫運算器：如果未指定其它物件，預設物件就是傳遞給指令碼所呼叫運算器的物件。這意味著您可以使用 [arc:set](./keyword-reference/op-arc-set) 將屬性寫入預設的未命名物件，這些屬性會作為輸入傳遞給指令碼中呼叫的下一個運算器。這是提供運算器必需參數的一種方式。
* 處理運算器或指令碼輸出中的當前物件：如果沒有為運算器結果指定變數名，則在呼叫該運算器的 [arc:call](./keyword-reference/op-arc-call) 塊中，預設物件會引用該運算器生成的當前物件。

透過省略 ArcScript 關鍵字的 item 屬性即可操作預設物件，如以下程式碼片段所示：

```xml theme={null}
<arc:set attr="path" value="." />
```

## 內建物件

除了指令碼中宣告的物件外，指令碼範圍內還提供多個內建物件。內建物件為存取 HTTP 請求、回應等組成部分提供介面。這些物件有助於將 HTTP 請求中的輸入對映到運算器輸入。

以下各節介紹這些內建物件。

### 指令碼輸入（\_input）

指令碼輸入可以從 `_input` 物件讀取。`_input` 物件包含指令碼執行時 URL 查詢字串中的變數和 POST 資料。如果 POST 資料中存在同名變數，則會覆蓋查詢字串中的值。

當您從指令碼中的預設物件讀取值時，實際上讀取的是 `_input` 中的值；同樣，寫入預設物件的屬性會與指令碼輸入一起作為參數傳遞給運算器。只有 info 塊或指令碼中定義的變數才可在 `_input` 物件中使用。

<Note>`_input` 在 [arc:call](./keyword-reference/op-arc-call) 塊內不是預設物件。如果需要存取它，必須按名稱引用。</Note>

### 指令碼輸出（\_out\[n]）

您可以透過預設物件或內建 `_outn` 物件存取 [arc:call](./keyword-reference/op-arc-call) 關鍵字生成的物件集中的當前物件，其中 `n` 是 [arc:call](./keyword-reference/op-arc-call) 關鍵字的巢狀級別。例如，如果位於單個 [arc:call](./keyword-reference/op-arc-call) 關鍵字內部，該物件名為 `_out1`。如果位於三層巢狀的 [arc:call](./keyword-reference/op-arc-call) 關鍵字內部，則物件名為 `_out3`。

### HTTP 請求（\_request）

您可以存取透過 URL 查詢字串傳入的變數、POST 到指令碼的變數，以及 `_request` 物件中作為屬性集合的其它變數。要存取特定的屬性集合，請使用集合名稱作為要讀取屬性的字首。例如，`[_request.qstring:name]` 讀取查詢字串中變數 “name” 的值，而 `[_request.form:name]` 讀取表單資料中變數 “name” 的值。

| 屬性                | 描述                                                                |
| ----------------- | ----------------------------------------------------------------- |
| `q[uery]string:*` | 存取查詢字串參數的值。                                                       |
| `form:*`          | 存取表單資料中的變數值。                                                      |
| `server:*`        | 存取伺服器變數的值。                                                        |
| `body`            | 存取請求的原始內容（主體）。                                                    |
| `bodybase64`      | 存取請求的 base64 編碼內容（主體）。                                            |
| `auth:*`          | 存取使用者的身分驗證資訊。使用 `[_request.auth:isauthenticated]` 判斷使用者是否已透過身分驗證。 |
| `other:*`         | 存取請求的其它資訊。使用 `[_request.other:applicationpath]` 檢索應用程式路徑。         |

### HTTP 回應（\_response）

`_response` 物件允許指令碼作者直接寫入 HTTP 回應。您可以設定以下屬性：

| 屬性                  | 描述                                                          |
| ------------------- | ----------------------------------------------------------- |
| `cookie:*`          | 在回應中設定 cookie。屬性名是帶有 `cookie:` 字首的 cookie 名稱，屬性值是 cookie 值。 |
| `writefile`         | 將指定路徑的內容寫入回應。                                               |
| `redirect`          | 將重新導向頭傳送到用戶端瀏覽器。這可用於將瀏覽器重新導向到另一個 URL。                       |
| `statuscode`        | 設定回應的 HTTP 狀態碼。                                             |
| `statusdescription` | 設定回應的 HTTP 狀態描述。                                            |

### HTTP 頭（\_httpheaders）

`_httpheaders` 物件可在指令碼和範本中輕鬆存取 HTTP 頭。您可以讀取此物件來讀取 HTTP 請求頭；也可以寫入此物件來寫入傳出回應頭。例如，可以使用如下行設定內容類型：

```xml theme={null}
<arc:set item="_httpheaders" attr="content-type" value="application/xml"/>
```

### HTTP Cookie（\_cookies）

使用 `_cookies` 物件可以檢索請求中的 cookie，並在回應中設定 cookie。包含多個 key/value 對的 cookie 會表示為與 cookie 的 key/value 對相對應的屬性集合。cookie 名稱會作為集合中每個屬性的字首。

### ASP.NET 會話（\_session）

ASP.NET 會話變數可透過 ArcScript 中的 `_session` 物件使用。儲存在會話中的任何物件都可以作為此物件的屬性存取。屬性名錶示用於在會話中儲存該物件的鍵。

### {siteName} 訊息（\_message）

當檔案透過 {siteNameShort} [流程](../flows/flows)時，應用程式會向檔案新增中繼資料。由原始檔案和應用程式中繼資料組成的結果稱為*訊息*。

`_message` 物件在指令碼上下文中提供對訊息正文和中繼資料的存取（也可在能夠解釋指令碼的端口欄位中使用，例如 [Email Send 端口](../connectors/email-send)中的**主題**欄位）。

<Note>ArcScript 中的陣列限制為 32768 個成員。如果訊息包含重複超過 32768 次的頭，則最舊的頭會從訊息中移除。</Note>

#### 中繼資料

訊息中繼資料包括：

* 一個唯一 ID（稱為 *MessageId*），無論檔名如何更改，它都可以識別檔案
* 處理過程中失敗和成功的資訊
* 在流程中以程式設計方式提升的任何自定義中繼資料

要存取訊息中繼資料，請使用 `_message` 物件的 `header:*` 屬性。例如，當在 {siteNameShort} 中處理檔案時發生錯誤，會向代表該檔案的訊息新增 `x-trapped-errordescription` 頭。此頭儲存有關所發生錯誤的資訊，包括髮生錯誤的 ConnectorId 以及錯誤的偵錯資訊。以下語法在指令碼上下文中引用此頭：

`[_message.header:x-trapped-errordescription]`

#### 正文

要存取訊息正文，請使用 `_message` 物件的 `body` 屬性，如下所示：

`[_message.body]`

這會以字串形式傳回訊息正文。

#### 新增跟蹤頭

要向訊息新增[跟蹤頭](../getting-started/administration/activity#tracked-headers)，請使用 `_message` 物件的 `trackedheader` 屬性，如下所示：

```xml theme={null}
<arc:set attr="output.filepath" value="[filepath]" />
<arc:set attr="_message.trackedheader:myHeaderName" value="Myvalue" />
<arc:push item="output" />
```

#### 新增自定義頭

要向檔案新增自定義頭，請設定端口推出的檔案物件的 `Header:header_name` 屬性。為清楚起見，先從一個指令碼開始，該指令碼將輸入檔案的未修改版本作為輸出推出：

```xml theme={null}
<arc:set attr="outfile.FilePath" value="[FilePath]" />
<arc:push item="outfile" />
```

`[FilePath]` 變數會解析為輸入檔案的完整路徑（和檔名），因此該指令碼會使輸出檔案與輸入檔案相同。

此指令碼中的以下新增內容會在推出檔案之前向檔案新增自定義頭：

```xml theme={null}
<arc:set attr="outfile.FilePath" value="[FilePath]" />
<arc:set attr="outfile.Header:myHeaderName" value="myValue" />
<arc:push item="outfile" />
```

要讓自定義頭可在日誌中搜尋，請導航到**設定 > 高階**頁面的**進階設定**部分中的**跟蹤頭**欄位，並新增頭名稱。

#### 記錄端口事件

要在 ArcScript 中向 `_message` 正文新增端口定義事件的日誌記錄，請向訊息新增 `log` 屬性字首、有效的日誌級別項目以及 `value`。以下範例向日志檔案新增一個 `Info` 行，其中包含屬性 `value` 部分的文字：

```xml theme={null}
<arc:set attr="_message.log:info" value="This is an info level log entry" />
```

有效的日誌級別項目如下：

* Error
* Warning
* Info
* Debug
* Trace

### 對映上下文（\_map）

`_map` 物件可在 [XML Map 端口](../connectors/xml-map/xml-map)中使用。在 `_map` 物件中設定的屬性始終可供後續對映使用（換言之，這些屬性不會被清除，且 `_map` 物件永遠不會超出範圍）。

`_map` 物件適合儲存在對映中某一點計算出來並在稍後引用的資訊。例如，涉及 EDI 文件的對映可能需要計算文件中*行專案*的數量，然後在文件末尾的 CTT 段中包含此計數值。可以將*行專案*計數計算並儲存為 `_map` 物件的屬性，隨後在 CTT 段對映中引用該屬性。

### 應用程式日誌（\_log）

`_log` 物件是進入 {siteNameShort} 應用程式日誌的掛鉤。將此物件的 `info` 屬性設定為字串，會使該字串顯示在應用程式日誌中。例如：

```xml theme={null}
<arc:set attr="_log.info" value="this string appears in the Application Log when the script executes" />
```

您可以在同一指令碼中多次設定此屬性，以將多條訊息記錄到應用程式日誌。無需清除或追加屬性值；按上例設定屬性值即可記錄指定值。

### {siteName} 端口（\_connector）

`_connector` 物件提供對當前端口欄位和屬性的存取。可用屬性與端口資料夾中 *port.cfg* 檔案裡儲存的值相同，應使用以下語法存取：

`[_connector.propertyName]`

<Note>使用此物件需要端口中的指令碼上下文。端口的**事件**索引標籤始終提供此上下文，部分端口還可以在特殊的可配置欄位中計算 ArcScript。</Note>

### 連接器狀態（\_state）

`_state` 物件提供限定到當前連接器例項的持久鍵值儲存。寫入 `_state` 的值會跨指令碼執行保留，適合重複檢測、查詢表、計數器以及其他需要記住先前值的場景。

所有 ArcScript 指令碼上下文均可使用 `_state`，包括：

* `beforeSend`、`afterSend` 和 `afterReceive` 等連接器事件
* [Script](../connectors/script) 和 [Python](../connectors/python) 連接器
* [XML Map](../connectors/xml-map/xml-map) 連接器

#### 範例

寫入值：

```xml theme={null}
<arc:set attr="_state.mykey" value="some value" />
```

讀取值（不存在的鍵傳回空值）：

```text theme={null}
[_state.mykey]
```

刪除一個鍵：

```xml theme={null}
<arc:unset attr="_state.mykey" />
```

刪除指令碼管理的全部鍵：

```xml theme={null}
<arc:unset attr="_state.*" />
```

該操作不會影響連接器自身的內部狀態項目。

##### 重複檔案檢測範例

```xml theme={null}
<arc:call op="messageRead" out="message">
  <arc:set attr="file.sha1hash" value="[message.data | sha1hash(true)]" />
</arc:call>
<!-- 文件名中的句点不能用于键名，因此先替换为下划线 -->
<arc:set attr="custom.key" value="[_input.filename | replace('.', '_')]" />
<arc:set attr="storedHash" value="[_state.[custom.key]]" />
<arc:if exp="![storedHash | def | equals([file.sha1hash])]">
  <arc:set attr="output.filepath" value="[_input.filepath]" />
  <arc:push item="output" />
  <arc:set attr="_state.[custom.key]" value="[file.sha1hash]" />
  <arc:else>
    <arc:throw code="match" desc="A file with name [_input.filename] and hash [file.sha1hash] was already processed." />
  </arc:else>
</arc:if>
```

#### 範圍

狀態限定到單個連接器例項，因此使用相同指令碼的兩個連接器不會共享狀態。指令碼寫入的鍵也會自動與連接器自身的內部狀態項目隔離。

#### 鍵名

鍵名遵循標準 ArcScript 屬性名規則：

| 字元  | 行為                                   |
| --- | ------------------------------------ |
| `@` | 作為命名空間字首，前面必須有名稱，例如 `test@`。         |
| `#` | 作為陣列字尾，前面必須有名稱；之後的文字必須是非零整數。         |
| `:` | 作為字首與名稱分隔符號；不允許第二個 `:`。              |
| `*` | 作為萬用字元；可出現多次，但不能位於 `#` 之後。           |
| `.` | 不允許，會產生 “Invalid attribute name” 錯誤。 |

值沒有字元限制。過長的鍵在儲存時會被自動截斷。檔名通常包含句點，因此將其用作鍵之前必須清理，並在讀寫時始終使用清理後的鍵：

```xml theme={null}
<arc:set attr="custom.key" value="[_input.filename | replace('.', '_')]" />
<arc:set attr="_state.[custom.key]" value="[file.sha1hash]" />
[_state.[custom.key]]
```
