Extract SmartArt Text and Delete Nodes with JavaScript in React

SmartArt graphics condense processes, hierarchies and cycles into a clear visual layout, but the text inside them can only be read or copied node by node. Turning the node contents into a checklist, importing them into another system, or searching them as plain text is slow and easy to miss by hand; outdated steps and redundant nodes also have to be removed one at a time in the editor.

This article uses Spire.Presentation for JavaScript to extract the text of PowerPoint SmartArt graphics in the browser, save it as text files, and delete unwanted nodes from a graphic. The whole process runs locally on the user's device through WebAssembly, requires no Office installation and no back-end service, and the presentation never leaves the browser.

The article covers two feature points:

For installation and project configuration, see Integrating Spire.Presentation for JavaScript in a React Project. The examples below assume that Spire.Presentation for JavaScript is installed and the WebAssembly module has been initialized.


Extract Text from Every SmartArt Graphic in the Presentation

A presentation often contains more than one graphic, and opening each slide to copy text by hand is slow. Collecting the SmartArt text from the whole file into a single text file makes the content easy to review, search and archive.

Code Result
ppt.Slides.Count The total number of slides in the presentation
shape instanceof pptModule.ISmartArt Checks whether a shape is a SmartArt graphic
shape.Nodes.Count The number of nodes in the graphic
shape.Nodes.get_Item(i).TextFrame.Text The text of the node at index i
window.dotnetRuntime.Module.FS.writeFile(fileName, text) Writes a string to a text file in the VFS

The steps are:

  1. Get the Spire.Presentation WASM module and make sure it is ready, then load the font and the presentation into the VFS.
  2. Create a Presentation object and call LoadFromFile() to load the presentation.
  3. Iterate the slides with Slides.Count, and check every shape on each slide for ISmartArt.
  4. For each graphic found, write a source heading, then iterate its nodes with Nodes.Count and read each text with TextFrame.Text into the list.
  5. Join the collected lines with \r\n and call window.dotnetRuntime.Module.FS.writeFile() to write them to a .txt file.
  6. Read the text file from the VFS to start the download, and release the presentation with Dispose().

The code to extract text from every SmartArt graphic in the presentation is as follows:

function App() {
  const extractAllSmartArt = async () => {
    // Get the Spire.Presentation WASM module
    const pptModule = window.wasmModule?.spirepresentation;

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

    // Load the font and the presentation into the VFS
    await window.spire.FetchFileToVFS('ARIAL.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
    const inputFileName = 'SmartArt.pptx';
    await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}data/`);

    // Load the presentation
    const ppt = new pptModule.Presentation();
    ppt.LoadFromFile(inputFileName);

    // Collect SmartArt text from every shape on every slide
    const lines = [];
    for (let s = 0; s < ppt.Slides.Count; s++) {
      const slide = ppt.Slides.get_Item(s);
      let graphicNo = 0;
      for (let i = 0; i < slide.Shapes.Count; i++) {
        const shape = slide.Shapes.get_Item(i);
        if (!(shape instanceof pptModule.ISmartArt)) continue;

        graphicNo++;
        lines.push(`Slide ${s + 1} · SmartArt ${graphicNo}`);
        for (let k = 0; k < shape.Nodes.Count; k++) {
          lines.push(shape.Nodes.get_Item(k).TextFrame.Text);
        }
      }
    }

    // Write the summary to a text file
    const outputFileName = 'ExtractAllSmartArtText.txt';
    window.dotnetRuntime.Module.FS.writeFile(outputFileName, lines.join('\r\n'));

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

    ppt.Dispose();
  };

  return (
    <div style={{ textAlign: 'center', height: '300px' }}>
      <h1>Summarize SmartArt Text</h1>
      <button onClick={extractAllSmartArt}>
        Summarize All
      </button>
    </div>
  );
}

export default App;

Text file after extracting text from every SmartArt graphic in the presentation:

Text file after extracting text from every SmartArt graphic in the presentation


Delete Nodes from a SmartArt Graphic

Placeholder steps and outdated stages make a graphic look cluttered. An organization chart arranges content by level, so deleting a node also means naming the level it sits on: you can remove a subordinate node from a node's child node collection, or delete the top-level node outright. The graphic re-flows around the remaining nodes and the other node texts stay unchanged; the result is saved to a new file, so the original presentation stays intact.

Code Result
smartArt.Nodes.get_Item(0) Gets the top-level node of the graphic
node.ChildNodes.RemoveNodeByPosition(position) Removes the child node at the given position under that node; later children move forward
smartArt.Nodes.RemoveNodeByPosition(position) Removes the top-level node at the given position; the remaining nodes re-flow
ppt.SaveToFile({ file, fileFormat }) Saves the modified presentation to a file in the VFS

The steps are:

  1. Get the Spire.Presentation WASM module and make sure it is ready, then load the font and the presentation into the VFS.
  2. Create a Presentation object, call LoadFromFile() to load the presentation, get the slide that holds the organization chart with Slides.get_Item(), and find the SmartArt graphic by iterating its shapes.
  3. Get the top-level root node with Nodes.get_Item(0) and call ChildNodes.RemoveNodeByPosition() to remove the child at the given position, where positions start at 0.
  4. Call Nodes.RemoveNodeByPosition() to remove the root node itself; the remaining nodes re-flow.
  5. Call Presentation.SaveToFile() to save the modified presentation as a new .pptx file.
  6. Read the result file from the VFS to start the download, and release the presentation with Dispose().

The code to delete nodes from a SmartArt graphic is as follows:

function App() {
  const removeSmartArtNode = async () => {
    // Get the Spire.Presentation WASM module
    const pptModule = window.wasmModule?.spirepresentation;

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

    // Load the font and the presentation into the VFS
    await window.spire.FetchFileToVFS('ARIAL.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
    const inputFileName = 'SmartArt.pptx';
    await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}data/`);

    // Load the presentation and get the second slide, which holds the organization chart
    const ppt = new pptModule.Presentation();
    ppt.LoadFromFile(inputFileName);
    const slide = ppt.Slides.get_Item(1);

    // Find the SmartArt graphic on the slide
    let smartArt = null;
    for (let i = 0; i < slide.Shapes.Count; i++) {
      const shape = slide.Shapes.get_Item(i);
      if (shape instanceof pptModule.ISmartArt) {
        smartArt = shape;
        break;
      }
    }

    // Get the top-level root node
    const root = smartArt.Nodes.get_Item(0);

    // Remove the child node at position 1 under the root (positions start at 0)
    root.ChildNodes.RemoveNodeByPosition(1);

    // Remove the root node itself
    smartArt.Nodes.RemoveNodeByPosition(0);

    // Save the result file
    const outputFileName = 'RemoveSmartArtNode.pptx';
    ppt.SaveToFile({ file: outputFileName, fileFormat: pptModule.FileFormat.Pptx2013 });

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

    ppt.Dispose();
  };

  return (
    <div style={{ textAlign: 'center', height: '300px' }}>
      <h1>Delete SmartArt Node</h1>
      <button onClick={removeSmartArtNode}>
        Delete Node
      </button>
    </div>
  );
}

export default App;

Presentation after deleting nodes from a SmartArt graphic:

Presentation after deleting nodes from a SmartArt graphic


FAQ

How to read child node text in a multi-level SmartArt graphic

Cause: Every node, including child nodes, is stored in the Nodes collection; ChildNodes returns only the direct children of a single node, so the two collections serve different purposes.

Solution: Iterate Nodes when every node text is needed; to read only the nodes under one specific node, read that node's ChildNodes:

for (let i = 0; i < smartArt.Nodes.Count; i++) {
  lines.push(smartArt.Nodes.get_Item(i).TextFrame.Text);
}

// read only the direct child nodes of the first node
const firstNode = smartArt.Nodes.get_Item(0);
for (let i = 0; i < firstNode.ChildNodes.Count; i++) {
  lines.push(firstNode.ChildNodes.get_Item(i).TextFrame.Text);
}

Why are the wrong nodes removed when deleting several nodes at once

Cause: Each removal moves the following nodes forward and renumbers their positions and indexes; continuing with positions recorded before the deletion then hits different nodes.

Solution: Iterate the collection backwards before deleting:

for (let i = smartArt.Nodes.Count - 1; i >= 0; i--) {
  const node = smartArt.Nodes.get_Item(i);
  if (node.TextFrame.Text === 'target text') {
    smartArt.Nodes.RemoveNode({ index: i });
  }
}

Does deleting the root node of an organization chart also delete its child nodes

Cause: RemoveNodeByPosition() removes only the node at the given position; it does not cascade to child nodes.

Solution: Remove the root node with a single call:

smartArt.Nodes.RemoveNodeByPosition(0);

The child nodes remain, one child is promoted to Level 0, the others keep Level 1, and positions are renumbered. To clear the whole graphic, remove the SmartArt shape with slide.Shapes.Remove(shape).


Get a Free License

If you wish to delete the evaluation message from the resulting documents, or to get rid of function limitations, please contact sales to obtain a valid 30-day temporary license.