npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

xml-disassembler

v2.2.3

Published

Disassemble XML into smaller, manageable files and reassemble on demand.

Downloads

570

Readme

xml-disassembler

NPM License Downloads/week Maintainability Code Coverage Known Vulnerabilities

Split large XML files into smaller, version-control–friendly pieces—then reassemble them when needed. Output as XML, JSON, JSON5, or YAML.

Useful for cleaner diffs, easier collaboration, and workflows like Salesforce metadata.

Native Rust: Core logic is in the xml-disassembler crate; this package provides Node.js bindings via Neon.


Table of contents


Quick start

import {
  DisassembleXMLFileHandler,
  ReassembleXMLFileHandler,
} from "xml-disassembler";

// Disassemble: one XML → many small files
const disassemble = new DisassembleXMLFileHandler();
await disassemble.disassemble({
  filePath: "path/to/YourFile.permissionset-meta.xml",
  uniqueIdElements:
    "application,apexClass,name,flow,object,recordType,tab,field",
  format: "json",
  strategy: "unique-id",
});

// Reassemble: many small files → one XML
const reassemble = new ReassembleXMLFileHandler();
await reassemble.reassemble({
  filePath: "path/to/YourFile",
  fileExtension: "permissionset-meta.xml",
});

Features

  • Disassemble – Break XML into smaller components (by unique ID or by tag).
  • Reassemble – Rebuild the original XML from disassembled output.
  • Multiple formats – Output (and reassemble from) XML, JSON, JSON5, or YAML.
  • Strategiesunique-id (one file per nested element) or grouped-by-tag (one file per tag).
  • Ignore rules – Exclude paths via a .xmldisassemblerignore file (same style as .gitignore).
  • Logging – Uses env_logger; set RUST_LOG for verbosity (e.g. RUST_LOG=debug).
  • Salesforce-friendly – Fits metadata and similar XML-heavy workflows.

Reassembly preserves element content and structure.


Install

npm install xml-disassembler

Disassembling

import { DisassembleXMLFileHandler } from "xml-disassembler";

const handler = new DisassembleXMLFileHandler();
await handler.disassemble({
  filePath: "test/baselines/general",
  uniqueIdElements:
    "application,apexClass,name,externalDataSource,flow,object,apexPage,recordType,tab,field",
  prePurge: true,
  postPurge: true,
  ignorePath: ".xmldisassemblerignore",
  format: "json",
  strategy: "unique-id",
});

| Option | Description | | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------- | | filePath | Path to the XML file or directory to disassemble. | | uniqueIdElements | Comma-separated element names used to derive filenames for nested elements. | | multiLevel | Optional. Multi-level spec: file_pattern:root_to_strip:unique_id_elements. See Multi-level disassembly. | | splitTags | Optional. With strategy: "grouped-by-tag": split or group nested tags. See Split tags. | | prePurge | Remove existing disassembly output before running (default: false). | | postPurge | Remove the source XML after disassembly (default: false). | | ignorePath | Path to the ignore file (default: .xmldisassemblerignore). | | format | Output format: xml, json, json5, yaml. | | strategy | unique-id or grouped-by-tag. |


Disassembly strategies

unique-id (default)

Each nested element is written to its own file, named by a unique identifier (or a SHA-256 hash if no UID is available). Leaf content stays in a file named after the original XML.

Best for fine-grained diffs and version control.

Example layouts

| Format | UID-based layout | Hash-based layout | | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | XML | XML UID | XML Hash | | YAML | YAML UID | YAML Hash | | JSON | JSON UID | JSON Hash | | JSON5 | JSON5 UID | JSON5 Hash |

grouped-by-tag

All nested elements with the same tag go into one file per tag. Leaf content stays in the base file named after the original XML.

Best for fewer files and quick inspection.

await handler.disassemble({
  filePath: "my.xml",
  strategy: "grouped-by-tag",
  format: "yaml",
});

Reassembly preserves element content and structure.

Split tags (splitTags)

With strategy: "grouped-by-tag", you can optionally split or group specific nested tags into subdirectories instead of a single file per tag. Useful for permission sets and similar metadata: e.g. one file per objectPermissions under objectPermissions/, and fieldPermissions grouped by object under fieldPermissions/.

Spec: Comma-separated rules. Each rule is tag:mode:field or tag:path:mode:field (path defaults to tag). mode is split (one file per array item, filename from field) or group (group array items by field, one file per group).

// Permission set: objectPermissions → one file per object; fieldPermissions → one file per field value
await handler.disassemble({
  filePath: "fixtures/split-tags/HR_Admin.permissionset-meta.xml",
  strategy: "grouped-by-tag",
  splitTags: "objectPermissions:split:object,fieldPermissions:group:field",
  format: "xml",
});

Creates HR_Admin/ with e.g. objectPermissions/Job_Request__c.objectPermissions-meta.xml, objectPermissions/Account.objectPermissions-meta.xml, fieldPermissions/<fieldValue>.fieldPermissions-meta.xml, plus the main HR_Admin.permissionset-meta.xml with the rest. Reassembly requires no changes: the existing reassemble command merges subdirs and files back into one XML.

Example layouts

| Format | Layout | | --------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | XML | XML tag | | YAML | YAML tag | | JSON | JSON tag | | JSON5 | JSON5 tag |


Multi-level disassembly

For XML with nested repeatable blocks (e.g. programProcesses inside LoyaltyProgramSetup), you can disassemble in one call and reassemble in one call. Pass a multi-level spec so the tool further splits matching files and later merges them in the right order.

Spec format: file_pattern:root_to_strip:unique_id_elements
Example: programProcesses:programProcesses:parameterName,ruleName — for files whose name contains programProcesses, strip the programProcesses root and disassemble by parameterName and ruleName.

import {
  DisassembleXMLFileHandler,
  ReassembleXMLFileHandler,
} from "xml-disassembler";

const disassemble = new DisassembleXMLFileHandler();
await disassemble.disassemble({
  filePath: "Cloud_Kicks_Inner_Circle.loyaltyProgramSetup-meta.xml",
  uniqueIdElements: "fullName,name,processName",
  multiLevel: "programProcesses:programProcesses:parameterName,ruleName",
  postPurge: true,
});

const reassemble = new ReassembleXMLFileHandler();
await reassemble.reassemble({
  filePath: "Cloud_Kicks_Inner_Circle",
  fileExtension: "loyaltyProgramSetup-meta.xml",
  postPurge: true,
});

| Option | Description | | ------------ | --------------------------------------------------------------------------- | | multiLevel | Optional. file_pattern:root_to_strip:unique_id_elements for nested split. |

A .multi_level.json config is written in the disassembly root so reassembly knows how to merge inner levels first, then the top level. No extra options are needed for reassembly.

Caveat: Multi-level reassembly removes disassembled directories after reassembling each level, even when you do not pass postPurge. This is required so the next level can merge the reassembled XML files. Use version control (e.g. Git) to recover the tree if needed, or run reassembly only in a pipeline where these changes can be discarded.


Reassembling

import { ReassembleXMLFileHandler } from "xml-disassembler";

const handler = new ReassembleXMLFileHandler();
await handler.reassemble({
  filePath: "test/baselines/general/HR_Admin",
  fileExtension: "permissionset-meta.xml",
  postPurge: true,
});

| Option | Description | | --------------- | --------------------------------------------------------------------------------- | | filePath | Directory that contains the disassembled files (e.g. HR_Admin/). | | fileExtension | Suffix for the rebuilt XML file (e.g. permissionset-meta.xml). Default: .xml. | | postPurge | Remove disassembled files after a successful reassembly (default: false). |


Ignore file

Exclude files or directories from disassembly using an ignore file (default: .xmldisassemblerignore). Syntax is the same as .gitignore (e.g. patterns, **/, negation).

Example:

# Skip these paths
**/secret.xml
**/generated/

Logging

The Rust crate uses env_logger. Set RUST_LOG to control verbosity (e.g. RUST_LOG=debug).


Implementation

The core logic is implemented in Rust (xml-disassembler) and exposed to Node.js via Neon. Building from source requires Rust and Node.js.


Use case

For a Salesforce CLI integration example, see sf-decomposer.


Contributing

See CONTRIBUTING.md for code style, PR process, and coverage expectations.


License

This project is based on a template by Allan Oricil; the original template code is under the ISC license. The xml-disassembler code is under the MIT license.