In corporate legal and compliance management scenarios, contract review is one of the most time-consuming and error-prone tasks. Every contract involves a large number of rights and obligations clauses — liquidated damages, payment terms, disclaimer clauses, breach liability, dispute resolution, and more. Any clause that is unfavorable to your side or ambiguously worded may lead to legal disputes or financial losses in the future. Traditional approaches rely on legal professionals reading and annotating each clause manually; a single contract of dozens of pages often takes hours, and review standards vary from person to person.

Comparison with Traditional SDK API Processing

Traditional Spire.Office for .NET API Spire.Agent.Office
Driving approach Write code to parse clauses one by one: load document → iterate paragraphs → regex match keywords → judge risk → highlight and annotate; every step requires code control Describe the review goal in natural language, and AI automatically identifies and annotates risk clauses
Code volume Requires a large amount of code to maintain the clause risk rule library, keyword matching, and annotation logic Only configuration code + 1 natural language instruction
Risk rules Risk judgment relies on hard-coded keywords; new risk types require code changes AI understands clauses semantically and can identify new risks not covered by the rules
Review stance Review logic for each contract type must be developed separately A single phrase like "review from our side" in the instruction switches the review stance
Maintainability The risk rule library requires continuous manual maintenance Review scope and rules can be adjusted at any time in natural language

This article explains how to use the Word AI capability of Spire.Agent.Office to review contract clauses and annotate risks. You can choose to highlight risk clauses on the original contract and add comments, or batch review and output a structured risk review report, meeting contract review needs of different scales and scenarios.

For product installation and SpireToken configuration, refer to Integrating Spire.Agent.Office in a .NET Project. The examples below assume Spire.Agent.Office is installed and SpireToken is configured.


Risk Clause Highlighting and Annotation

Risk clause highlighting and annotation suits in-depth review of important contracts. The core idea is: let AI review contract clauses one by one, identify clauses that are unfavorable to your side or carry legal risks, highlight them in yellow in place and add comments, so legal professionals can view the risk points directly on the contract.

using Spire.Agent.Office.AI;
using Spire.Agent.Office.Extensions;
using Spire.Doc;

// Path of the contract file to be reviewed
string inputPath = "E:\\Input\\Software_Contract.docx";
// Save path
string savePath = "E:\\Output\\Review.docx";
// Output directory
string OutDir = "E:\\Output";
// SpireToken Key
string key = "xxxxx";
// Natural language instruction
string instruction =
    "Review all clauses in the current contract document and identify clauses that are unfavorable to the purchaser or carry legal risks, including but not limited to: " +
    "excessively high liquidated damages, stringent payment terms, overly broad disclaimer clauses, missing breach liability provisions, unfavorable court jurisdiction agreements, unclear intellectual property ownership, etc. " +
    "For each risk clause, perform the following operations: 1. Highlight the risk clause text in yellow; 2. Add a comment in place, noting the risk point, risk level (high/medium/low), and modification suggestions. " +
    "After processing, keep the same layout, styles, and fonts as the original document, and finally save and output in DOCX format";

// Call the Word document processing function
AIResult result = ExecuteDemoWord(instruction, inputPath, savePath, key, OutDir, null);

// Execute Word document AI processing
static AIResult ExecuteDemoWord(string instruction, string inputPath, string savePath, string key, string output, string[] attachmentPaths)
{
    // Create an AIOptions configuration object
    AIOptions options = new AIOptions();
    // Set the working directory to the output directory
    options.WorkDir = output;
    // Set the SpireToken Key
    options.SpireToken = key;

    // Use the Document object to process the Word document
    using (Document doc = new Document())
    {
        // Load the contract document from file
        if (!string.IsNullOrEmpty(inputPath) && File.Exists(inputPath))
        {
            doc.LoadFromFile(inputPath);
        }
        // Create the AI document processor
        AIDocumentProcessor processor = doc.AI(options);

        // Execute the AI instruction
        return processor.ExecuteInstruction(doc, instruction, savePath, attachmentPaths);
    }
}

Contract after AI highlighting and annotation Contract with highlighted annotations

In the reviewed contract, risk clauses are highlighted in yellow, and the comments clearly state the risk points and modification suggestions. Legal professionals can quickly locate the highlighted positions without reading the original text line by line, and can directly discuss modification plans with the business side based on the comments.


Batch Review and Review Report

For quick screening of large batches of contracts (such as contract renewal or supplier qualification review), batch review with a structured review report is more suitable. The core idea is: let AI review multiple contracts one by one, consolidate the risk clauses of each contract into a risk list, and output it as an MD report for statistics, tracking, and tiered processing.

using Spire.Agent.Office.AI;
using Spire.Agent.Office.Extensions;
using Spire.Doc;

// Paths of multiple contract files to be reviewed
string[] attachments = new string[] {
    "E:\\Input\\Purchase_Contract_EN.docx",   // Purchase contract
    "E:\\Input\\Sales_Contract_EN.docx",   // Sales contract
    "E:\\Input\\Labor_Contract_EN.docx"    // Labor contract
};
// Save path (null here; the output folder path set below will be used)
string savePath = "E:\\Output\\Structural_Review_Output.md";
// Output directory
string OutDir = "E:\\Output";
// SpireToken Key
string key = "xxxxx";
// Natural language instruction
string instruction =
    "Review the contract documents in the attachments one by one, extract risk clauses, and output a Markdown review report: " +
    "The report contains a table with fixed columns: Contract Name | Clause Number | Clause Original Text | Risk Level (High/Medium/Low) | Risk Type | Risk Description | Modification Suggestion. " +
    "Sort by risk level from high to low; the clause original text must be quoted from the contract, truncated with … after 20 characters, and must not be fabricated.";

// Call the Word document processing function
AIResult result = ExecuteDemoWord(instruction, savePath, key, OutDir, attachments);

// Execute Word document AI processing
static AIResult ExecuteDemoWord(string instruction, string savePath, string key, string output, string[] attachments)
{
    // Create an AIOptions configuration object
    AIOptions options = new AIOptions();
    // Set the working directory to the output directory
    options.WorkDir = output;
    // Set the SpireToken Key
    options.SpireToken = key;

    // Use the Document object to process the Word document
    using (Document doc = new Document())
    {
        // Create the AI document processor
        AIDocumentProcessor processor = doc.AI(options);

        // Execute the AI instruction
        return processor.ExecuteInstruction(doc, instruction, savePath, attachments);
    }
}

Contract risk review report output by AI Contract risk review report

Each row in the review report corresponds to a risk clause and contains the clause original text, risk level, risk type, and modification suggestion. Legal professionals can sort by risk level to prioritize high-risk clauses, or export the report for risk ledger tracking in a contract management system.


FAQ

Risk clauses identified inaccurately

Reason: AI's judgment of "unfavorable clauses" depends on the review stance. From your side's perspective versus the counterparty's perspective, the risk judgment for the same clause may be completely opposite.

Solution: Specify the review stance clearly in the instruction, such as "review from the purchaser's perspective", and add a list of risk types to focus on. AI will strictly follow this stance and scope.

Document style changes after highlighting

Reason: The AI model automatically modified or added content during processing.

Solution: Add a description such as "keep the same layout, styles, and fonts as the original document" to the instruction.

Review report does not accurately correspond to contract clauses

Reason: Clause numbers are inconsistent, or the same clause is scattered across multiple places in the contract, causing the clause original text in the report to not match the contract.

Solution: In the instruction, require AI to quote the clause original text and note the source of the clause number, for easy manual verification and location.


Get the SpireToken Key

Configure it in your code:

AIOptions options = new AIOptions();
options.SpireToken = key;

Reconciliation is one of the most frequent and tedious tasks in corporate finance, and the source data often comes in different forms: bank statements are CSV files exported from online banking, while system transaction records may be PDF detail reports. The two tables have different column names, inconsistent date and amount formats, and even stray spaces and missing values. This article shows how to use Spire.Agent.Office Excel AI capabilities to automatically read CSV and PDF data sources, identify and map column names, clean the data, and finally generate an Excel reconciliation detail report.

For product installation and SpireToken configuration, please refer to Integrate Spire.Agent.Office in a .NET Project. The following examples assume Spire.Agent.Office is installed and SpireToken is configured.


Reconcile by Statement Number

Reconcile and analyze the CSV-format bank statement with the PDF-format system transaction records by statement number.

using Spire.Agent.Office.AI;
using Spire.Agent.Office.Extensions;
using Spire.Xls;

// Data source files: bank statement (CSV) and system transaction records (PDF)
string[] attachmentPaths = new string[]
{
    @"bank-statement.csv",   
    @"system-records.pdf"    
};

// Excel processing configuration
string inputPath = "";  
string savePath = "out.xlsx";  
// SpireToken Key
string key = "**************************"; 
string instruction =
    "Reconcile the bank statement (CSV) with the system transaction records (PDF) in the attachments: " +
    "1. Establish the column mapping of the two tables by semantics: transaction date, amount, counterparty account, description, statement number; " +
    "2. Cleaning: strip leading/trailing and internal extra spaces from text; write dates as yyyy-MM-dd text; convert amounts to numbers by removing currency symbols and thousands separators; mark empty description or empty counterparty as 'Unknown', mark empty amount as 'Amount missing'; " +
    "3. Match row by row using the statement number as the unique key, and mark the status: 'Matched'/'Amount mismatch'/'Bank only'/'System only'; " +
    "4. Generate a 'Reconciliation Detail' worksheet: each record with bank amount, system amount, difference, status and remark; " +
    "5. Highlight difference rows: yellow for amount mismatch, orange for bank only, blue for system only; " +
    "Finally save the output as an Excel file";

// Call the Excel document processing function
AIResult result = ExecuteDemoExcel(instruction, inputPath, savePath, key,  attachmentPaths);


// Execute Excel document AI processing
static AIResult ExecuteDemoExcel(string instruction, string inputPath, string savePath, string key, string[] attachmentPaths)
{
    // Create an AIOptions configuration object
    AIOptions options = new AIOptions();
    options.SpireToken = key; 

    // Use the Workbook object to process the Excel document
    using (Workbook workbook = new Workbook())
    {
        // Load the Excel template from a file
        if (!string.IsNullOrEmpty(inputPath) && File.Exists(inputPath))
        {
            workbook.LoadFromFile(inputPath);
        }
        // Create the AI document processor
        AIWorkbookProcessor processor = workbook.AI(options);

        // Execute the AI instruction
        return processor.ExecuteInstruction(workbook, instruction, savePath, attachmentPaths);
    }
}

Original bank statement CSV Original bank statement CSV Original system transaction PDF Original system transaction PDF Reconciliation detail after Excel AI reconciliation Reconciliation detail after Excel AI reconciliation


Reconcile by Date and Amount Combination

When the data source does not contain a unique statement number, you can use the "transaction date + amount" combination as the matching key for reconciliation: first group by date, then pair the records by amount within the same date.

using Spire.Agent.Office.AI;
using Spire.Agent.Office.Extensions;
using Spire.Xls;

// Data source files without statement numbers: bank statement (CSV) and system transaction records (PDF)
string[] attachmentPaths = new string[]
{
    @"bank-statement-noId.csv",   
    @"system-records-noId.pdf"   
};

// Excel processing configuration
string inputPath = "";  
string savePath = "out.xlsx";  
// SpireToken Key
string key = "**************************";  
string instruction =
    "Reconcile the bank statement (CSV) with the system transaction records (PDF) in the attachments: " +
    "1. Establish the column mapping of the two tables by semantics: transaction date, amount, counterparty account, description; " +
    "2. Cleaning: strip extra spaces from text; write dates as yyyy-MM-dd text; convert amounts to numbers; mark missing values as 'Unknown' or 'Amount missing'; " +
    "3. Use the 'transaction date + amount' combination as the matching key: first group by date, then pair the records by amount within the same date, and mark the status: 'Matched'/'Amount mismatch'/'Bank only'/'System only'; " +
    "4. Generate a 'Reconciliation Detail' worksheet (bank amount, system amount, difference, status); " +
    "5. Highlight difference rows: yellow for amount mismatch, orange for bank only, blue for system only; " +
    "Finally save the output as an Excel file";

// Call the Excel document processing function
AIResult result = ExecuteDemoExcel(instruction, inputPath, savePath, key,  attachmentPaths);


// Execute Excel document AI processing
static AIResult ExecuteDemoExcel(string instruction, string inputPath, string savePath, string key, string[] attachmentPaths)
{
    // Create an AIOptions configuration object
    AIOptions options = new AIOptions();
    options.SpireToken = key; 

    // Use the Workbook object to process the Excel document
    using (Workbook workbook = new Workbook())
    {
        // Load the Excel template from a file
        if (!string.IsNullOrEmpty(inputPath) && File.Exists(inputPath))
        {
            workbook.LoadFromFile(inputPath);
        }
        // Create the AI document processor
        AIWorkbookProcessor processor = workbook.AI(options);

        // Execute the AI instruction
        return processor.ExecuteInstruction(workbook, instruction, savePath, attachmentPaths);
    }
}

Original bank statement CSV Original bank statement CSV Original system transaction PDF Original system transaction PDF Reconciliation detail after Excel AI reconciliation Reconciliation detail after Excel AI reconciliation


Comparison with Traditional SDK API Processing

Traditional Spire.Office for .NET API Spire.Agent.Office Processing
Driving approach Requires writing large amounts of code for CSV/PDF parsing, column mapping, data cleaning, matching and exception logic Describe reconciliation rules in natural language, and AI understands and orchestrates the execution automatically
Data format CSV and PDF must be parsed with different components, each with its own format Directly attach CSV and PDF, and AI understands the content automatically
Field mapping Hard-coded column name mappings; changing column names or formats requires code changes AI maps columns automatically based on column names and content semantics
Exception handling Need to hand-write difference judgment, alert text and style logic AI automatically identifies differences and provides handling suggestions

Frequently Asked Questions

Inconsistent date and amount formats in the bank statement CSV

Cause: In the CSV exported from online banking, dates may be written as 2026-07-01, 2026/7/1, etc., and amounts may carry , thousands separators, or leading/trailing spaces, leading to misjudgment during matching.

Solution: Explicitly require in the instruction "unify dates as yyyy-MM-dd and amounts as numeric formats and remove spaces", and AI will complete the standardization automatically before reconciliation.

The system transaction PDF table spans pages or has headers/footers

Cause: PDF detail reports may have pagination, repeated headers, or footer annotations, which affect AI's reading of the table data.

Solution: Add "ignore headers/footers and repeated header rows, only read the table data rows" to the instruction.

The same amount appears multiple times on the same day, causing mismatches

Cause: When reconciling by the "date + amount" combination, there may be multiple transactions with the same amount on the same day, making the exact correspondence impossible to determine.

Solution: Prefer precise reconciliation by statement number; if there is really no statement number, you can require in the instruction to "mark records that cannot be matched one-to-one on the same day as 'Amount mismatch'".


Get a SpireToken Key

Configure it in code:

AIOptions options = new AIOptions();
options.SpireToken = key;

Operating Excel files as streams in web applications allows developers to dynamically create, load, modify, and save Excel files, enabling flexible and efficient data processing. Spire.XLS for JavaScript runs entirely in the browser via WebAssembly, using a virtual file system (VFS) to manage input and output files — no backend server is required. It provides a simple, easy-to-use Stream API that makes creating and saving Excel files through streams more convenient.

Working with streams greatly reduces direct disk I/O operations, improving application performance and responsiveness, especially in scenarios that involve real-time data processing or limited storage. With Spire.XLS for JavaScript, you can dynamically create an Excel file and save it to a stream, load and read workbook data from a stream, or modify content in a stream and save it as a new Excel file — all directly in the browser, simplifying data exchange and system integration.

This article covers three core features:

For installation and project setup, refer to Integrating Spire.XLS for JavaScript in a React Project. The examples below assume Spire.XLS is installed and the WebAssembly module is initialized.


Dynamically Create an Excel File and Save It to a Stream

With Spire.XLS for JavaScript, you can dynamically create an Excel file in the browser, fill it with data and formatting, and then save the workbook to a file stream via the SaveToStream() method. This approach eliminates the need to store files directly on disk while improving application performance and responsiveness. The steps are as follows:

  • Create a Workbook instance to generate a new Excel workbook, clear the default worksheets, and add a new worksheet.
  • Access a specific worksheet using the Worksheets.get() method.
  • Define the data to write to the worksheet, for example, organizing data with a two-dimensional array.
  • Use the Range.get_Item() method to access cells and set their values one by one.
  • Format the worksheet cells, such as setting colors, fonts, borders, or adjusting column widths.
  • Create a Stream object and save the workbook to the file stream using the SaveToStream() method. The saved stream can be used for further processing, such as downloading as a file or transferring over the network.

Below is a complete code example demonstrating how to dynamically create an Excel file and save it to a stream in React:

function App() {
  const createAndSaveToStream = async () => {
    // Get the Spire.XLS WASM module
    const xlsModule = window.wasmModule?.spirexls;

    // Check if the module is ready
    if (!xlsModule) {
      alert('Spire.Xls is not ready yet');
      return;
    }

    // Load the font file to ensure proper text rendering
    await window.spire.FetchFileToVFS('ARIAL.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}font/`);

    // Create a new workbook instance
    const workbook = new xlsModule.Workbook();

    // Clear the default worksheets and add a new worksheet
    workbook.Worksheets.Clear();
    const sheet = workbook.Worksheets.Add('Data');

    // Define the sample data to write to the worksheet (two-dimensional array)
    const headers = ['ID', 'Name', 'Age', 'Country', 'Salary (¥)'];
    const data = [
      [1, 'Zhang Wei', 29, 'China', 8000],
      [2, 'Li Na', 35, 'China', 12000],
      [3, 'Wang Qiang', 42, 'China', 15000],
      [4, 'Jack', 26, 'USA', 9500],
      [5, 'Chen Si', 31, 'China', 11000],
      [6, 'Ishihara Yasuko', 28, 'Japan', 8800]
    ];

    // Write the headers to the first row
    for (let col = 0; col < headers.length; col++) {
      sheet.Range.get_Item({ row: 1, column: col + 1 }).Text = headers[col];
    }

    // Write the data to the following rows
    for (let row = 0; row < data.length; row++) {
      for (let col = 0; col < data[row].length; col++) {
        sheet.Range.get_Item({ row: row + 2, column: col + 1 }).Text = String(data[row][col]);
      }
    }

    // Format the header row
    sheet.Range.get('A1:E1').Style.Color = xlsModule.Color.get_LightSkyBlue();
    sheet.Range.get('A1:E1').Style.Font.FontName = 'Arial';
    sheet.Range.get('A1:E1').Style.Font.Size = 12;
    sheet.Range.get('A1:E1').Style.Font.IsBold = true;

    // Format the data rows
    for (let i = 2; i <= data.length + 1; i++) {
      const dataRange = sheet.Range.get({
        row: i, column: 1,
        lastRow: i, lastColumn: headers.length
      });
      dataRange.Style.Color = xlsModule.Color.get_LightGray();
      dataRange.Style.Font.FontName = 'Arial';
      dataRange.Style.Font.Size = 11;
    }

    // Add borders to the header and all data cells
    const usedRange = sheet.Range.get({
      row: 1, column: 1,
      lastRow: data.length + 1,
      lastColumn: headers.length
    });
    usedRange.Borders.LineStyle = xlsModule.LineStyleType.Thin;
    usedRange.Borders.Color = xlsModule.Color.get_LightSteelBlue();

    // Adjust column widths to fit the content
    for (let col = 1; col <= headers.length; col++) {
      sheet.AutoFitColumn(col);
    }

    // Create a stream and save the workbook to it
    const outputFileName = 'CreateExcelToStream.xlsx';
    const fileStream = new xlsModule.Stream(outputFileName);
    workbook.SaveToStream(fileStream, xlsModule.FileFormat.Version2010);

    // Dispose of the workbook object to release resources
    workbook.Dispose();

    // Read the file from VFS and trigger download
    const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
    const blob = new Blob([fileArray], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = outputFileName;
    a.click();
    URL.revokeObjectURL(url);
  };

  return (
    <div style={{ textAlign: 'center', height: '300px' }}>
      <h1>Create Excel and Save to Stream</h1>
      <button onClick={createAndSaveToStream}>
        Generate
      </button>
    </div>
  );
}

export default App;

Excel file dynamically created and saved to a stream with Spire.XLS for JavaScript

Excel file dynamically created and saved to a stream with Spire.XLS for JavaScript


Load and Read an Excel File from a Stream

With Spire.XLS for JavaScript, you can load an Excel file directly from a stream using the LoadFromStream() method. Once loaded, the cell data of the Excel file in the stream can be easily read, enabling fast and flexible data processing without file I/O operations. The steps are as follows:

  • Create a Stream object pointing to the Excel file to be loaded.
  • Create a Workbook object and load the file from the stream using the LoadFromStream() method.
  • Get the first worksheet using the Worksheets.get() method.
  • Iterate through the rows and columns of the worksheet and extract cell data using the Range.get() method.
  • Display the extracted data on the page, or use it for other operations.

Below is a complete code example demonstrating how to load and read an Excel file from a stream in React:

import React, { useState } from 'react';

function App() {
  const [extractedData, setExtractedData] = useState('');

  const loadAndReadFromStream = async () => {
    // Get the Spire.XLS WASM module
    const xlsModule = window.wasmModule?.spirexls;

    // Check if the module is ready
    if (!xlsModule) {
      alert('Spire.Xls is not ready yet');
      return;
    }

    // Load the font file to ensure proper text rendering
    await window.spire.FetchFileToVFS('ARIAL.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}font/`);

    // Load the sample Excel file into VFS
    await window.spire.FetchFileToVFS('Sample.xlsx', '', `${process.env.PUBLIC_URL}data/`);

    // Create a workbook object and load the Excel file from a stream
    const workbook = new xlsModule.Workbook();
    const fileStream = new xlsModule.Stream('Sample.xlsx');
    workbook.LoadFromStream(fileStream, xlsModule.FileFormat.Auto);

    // Get the first worksheet of the workbook
    const sheet = workbook.Worksheets.get(0);

    // Iterate through the rows and columns to extract cell data
    const data = [];
    for (let row = sheet.FirstRow; row <= sheet.LastRow; row++) {
      const line = [];
      for (let col = sheet.FirstColumn; col <= sheet.LastColumn; col++) {
        line.push(sheet.Range.get({ row: row, column: col }).Text);
      }
      data.push(line.join(' | '));
    }

    // Dispose of the workbook object to release resources
    workbook.Dispose();

    // Display the extracted data on the page
    setExtractedData(data.join('\n'));
  };

  return (
    <div style={{ textAlign: 'center', height: '300px' }}>
      <h1>Load and Read Excel Data from Stream</h1>
      <button onClick={loadAndReadFromStream}>
        Read
      </button>
      <pre style={{ marginTop: '20px', textAlign: 'left' }}>{extractedData}</pre>
    </div>
  );
}

export default App;

Excel file loaded and read from a stream with Spire.XLS for JavaScript

Excel file loaded and read from a stream with Spire.XLS for JavaScript


Modify and Save an Excel File in a Stream

With Spire.XLS for JavaScript, you can modify an Excel file in memory. First load the Excel file in the stream into a Workbook object via the LoadFromStream() method; after completing modifications such as changing cell styles or content, save the file back to a stream using the SaveToStream() method. This enables real-time changes to Excel file data without relying on direct file storage operations. The steps are as follows:

  • Create a Stream object pointing to the Excel file and load the file from the stream via the LoadFromStream() method.
  • Access the worksheet using the Worksheets.get() method.
  • Modify the styles of the header row and data rows (font name, size, background color, etc.) through the CellRange.Style property.
  • Use the AutoFitColumn() method to automatically adjust column widths to fit the content.
  • Set the border style of the cells.
  • Create a new Stream object, save the modified workbook to the stream using the SaveToStream() method, read the result file from VFS, and trigger the download.

Below is a complete code example demonstrating how to modify and save an Excel file in a stream in React:

function App() {
  const modifyAndSaveInStream = async () => {
    // Get the Spire.XLS WASM module
    const xlsModule = window.wasmModule?.spirexls;

    // Check if the module is ready
    if (!xlsModule) {
      alert('Spire.Xls is not ready yet');
      return;
    }

    // Load the font file to ensure proper text rendering
    await window.spire.FetchFileToVFS('ARIAL.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}font/`);

    // Load the sample Excel file into VFS
    await window.spire.FetchFileToVFS('Sample.xlsx', '', `${process.env.PUBLIC_URL}data/`);

    // Create a workbook object and load the Excel file from a stream
    const workbook = new xlsModule.Workbook();
    const fileStream = new xlsModule.Stream('Sample.xlsx');
    workbook.LoadFromStream(fileStream, xlsModule.FileFormat.Auto);

    // Get the first worksheet of the workbook
    const sheet = workbook.Worksheets.get(0);

    // Modify the style of the header row
    const headerRow = sheet.Range.get({
      row: sheet.FirstRow, column: sheet.FirstColumn,
      lastRow: sheet.FirstRow, lastColumn: sheet.LastColumn
    });
    headerRow.Style.Font.FontName = 'Arial';
    headerRow.Style.Font.Size = 12;
    headerRow.Style.Font.IsBold = true;
    headerRow.Style.Color = xlsModule.Color.get_LightSkyBlue();

    // Modify the styles of the data rows, with alternating colors (even rows)
    for (let i = sheet.FirstRow + 1; i <= sheet.LastRow; i++) {
      const dataRow = sheet.Range.get({
        row: i, column: sheet.FirstColumn,
        lastRow: i, lastColumn: sheet.LastColumn
      });
      dataRow.Style.Font.FontName = 'Arial';
      dataRow.Style.Font.Size = 10;
      dataRow.Style.Color = xlsModule.Color.get_LightGray();
      if (i % 2 === 0) {
        dataRow.Style.Color = xlsModule.Color.get_DarkGray();
      }
    }

    // Adjust column widths to fit the content
    for (let col = sheet.FirstColumn; col <= sheet.LastColumn; col++) {
      sheet.AutoFitColumn(col);
    }

    // Set the border color
    sheet.AllocatedRange.Borders.Color = xlsModule.Color.get_White();

    // Save the modified workbook to a new stream
    const outputFileName = 'ModifyExcelInStream.xlsx';
    const outStream = new xlsModule.Stream(outputFileName);
    workbook.SaveToStream(outStream, xlsModule.FileFormat.Version2010);

    // Dispose of the workbook object to release resources
    workbook.Dispose();

    // Read the file from VFS and trigger download
    const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
    const blob = new Blob([fileArray], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = outputFileName;
    a.click();
    URL.revokeObjectURL(url);
  };

  return (
    <div style={{ textAlign: 'center', height: '300px' }}>
      <h1>Modify and Save Excel in Stream</h1>
      <button onClick={modifyAndSaveInStream}>
        Generate
      </button>
    </div>
  );
}

export default App;

Excel file modified and saved in a stream with Spire.XLS for JavaScript

Excel file modified and saved in a stream with Spire.XLS for JavaScript


FAQ

How to handle the stream-saved file being unable to open in Excel?

Cause: When saving a workbook via the SaveToStream() method, if the correct output file format is not specified through the FileFormat parameter, the generated file format may not match its extension, causing it to fail to open properly.

Solution: Specify a concrete file format enum value when saving to a stream, such as xlsModule.FileFormat.Version2010:

const fileStream = new xlsModule.Stream(outputFileName);
workbook.SaveToStream(fileStream, xlsModule.FileFormat.Version2010);

How to ensure the workbook loaded from a stream correctly recognizes the file format?

Cause: The LoadFromStream() method needs to identify the file type based on the actual format of the stream data. If the format parameter is set incorrectly, loading may fail or data parsing may produce errors.

Solution: Use xlsModule.FileFormat.Auto when loading so that the library automatically detects the format of the file in the stream:

const fileStream = new xlsModule.Stream('Sample.xlsx');
workbook.LoadFromStream(fileStream, xlsModule.FileFormat.Auto);

Get a Free License

Spire.XLS for JavaScript offers a 30-day full-featured free trial license with no functional limitations. Apply here to evaluate before purchasing.

Page 4 of 346
page 4