Copy a worksheet using streaming XML

Copying a worksheet with a streaming parser is useful for large sheets because the cell XML can be processed without loading a full worksheet object model.

The upstream page compares two approaches. DOM-style copying is simpler because a worksheet tree can be cloned as a whole, but it loads the full part into memory. Streaming XML copying reads and writes elements forward-only, which is better for very large worksheet parts.

Package model

A copied worksheet needs more than copied XML. The workbook must get a new <sheet/> entry and relationship, and any worksheet-owned relationships may need to be copied or adjusted.

<sheet name="Copied Sheet" sheetId="3" r:id="rId3"/>

Even if the worksheet XML is streamed, the workbook sheets collection is usually small. Updating that workbook list with a structured approach is safer than trying to stream-prepend a new sheet entry and accidentally change sheet order.

Rust workflow

Copy the source worksheet XML into a new worksheet part and append a workbook sheet entry:

#![allow(unused)]
fn main() {
pub fn copy_worksheet(
  path: &Path,
  source_sheet_name: &str,
  new_sheet_name: &str,
) -> Result<Vec<u8>, Box<dyn std::error::Error>> {
  let mut document = SpreadsheetDocument::new_from_file_with_settings(path, lazy_settings())?;
  let workbook_part = document.workbook_part()?;
  let source_part = worksheet_part_by_name(&document, &workbook_part, source_sheet_name)?;
  let copied_xml = source_part
    .data_as_str(&document)?
    .unwrap_or_default()
    .to_string();
  let new_part = workbook_part.add_new_part_auto_id::<_, WorksheetPart>(&mut document)?;
  new_part.set_data(&mut document, copied_xml.into_bytes())?;
  let relationship_id = workbook_part
    .get_id_of_part(&document, &new_part)
    .expect("worksheet relationship id")
    .to_string();
  let workbook_xml = workbook_part.data_as_str(&document)?.unwrap_or_default();
  let updated_workbook_xml = append_sheet(workbook_xml, new_sheet_name, &relationship_id)?;

  workbook_part.set_data(&mut document, updated_workbook_xml.into_bytes())?;

  let mut buffer = Cursor::new(Vec::new());
  document.save(&mut buffer)?;
  Ok(buffer.into_inner())
}
}

If the source worksheet owns drawings, tables, comments, printer settings, or other related parts, copy those relationships and rewrite references in the copied worksheet as needed. The example above covers the worksheet XML, workbook relationship, and workbook sheet list.