Skip to main content

Bulk Editor for FactoryTalk Batch Recipes

CI Publish Coverage PyPI version

A command-line tool that lets you bulk-edit Rockwell FactoryTalk Batch S88 recipes (.pxml, .uxml, and .oxml) using Excel. You can export your recipes into a spreadsheet, make bulk changes to parameters and formula-values, then import the edits back to produce updated XML files. It will presere element order, empty tags, and original structure.

[!NOTE] Useful for large recipes with many defered parameters


Table of Contents

Features

  1. Bulk Editing in Excel

    • Extract top-level <Parameter> and step-level <FormulaValue> into one sheet per file.
    • Edit hundreds of tags in your favorite spreadsheet tool.
  2. Preserve Order & Empties

    • Maintains the original element order.
    • Keeps empty tags (e.g. <EngineeringUnits/>, <String/>).
    • Retains existing <FormulaValueLimit> blocks unless you remove them.
  3. Recursive Child Parsing

    • A .pxml may reference .uxml; a .uxml may reference .oxml via <StepRecipeID>.
    • Exports all related files into one workbook.
  4. Selective Create/Update/Delete

    • Update if a row’s FullPath matches an existing node.
    • Delete if you remove a row entirely.
    • Create if you add a new FullPath row (with one valid data-type column).
  5. Detailed Logging

    • Console keeps high-signal warnings/summaries with Rich formatting.
    • DEBUG-level detail (with --debug) is written to batch_bulk_editor.log.
  6. ParamExpression support

    • For FormulaValues you can now supply a real‐time expression.
    • In Excel, fill the appropriate data‐type column (Real/Integer/String) with the literal ParamExpression, and put the actual expression into the new ParamExpression column (appearing right after Defer).
    • On import, the tool will generate a <ParamExpression/> tag, insert your formula into <Real> (or <Integer>, etc.), and preserve correct XML ordering.

cli

cli-results


Requirements

  • Python 3.14 (in theory 3.10+)
  • Dependencies
    • For xml and excel work:
      • lxml
      • openpyxl
    • For CLI:
      • typer

Installation

Installation

Using pip

  1. Clone this repo.

  2. Install dependencies:

    pip ftbatch-bulk-edit
    
  3. Run:

    ftbatch-bulk-edit xml2excel --xml yourRecipe.pxml --excel out.xlsx
    

Using uv as the Package Manager

uv sync --python 3.14
uv run python app/main.py xml2excel --xml yourRecipe.pxml --excel out.xlsx

Using the example in the repo

uv run python app/main.py --progress xml2excel --xml tests/examples/LNP/P_LNP.PXML --excel tests/examples/converted-outputs/output.xlsx

Using the Justfile (Recommended)

We provide a justfile to automate setup, testing, linting, coverage, and executable builds:

just help         # list recipes
just sync         # install deps for Python 3.14
just ci-check     # CI parity (lint + tests + coverage threshold)
just test         # run tests
just lint         # run Ruff lint checks
just cov          # run tests with coverage threshold
just package      # build sdist/wheel + twine check + smoke tests
UV_PUBLISH_TOKEN=... just publish-testpypi-dry   # TestPyPI auth/check dry-run
UV_PUBLISH_TOKEN=... just publish-testpypi       # publish to TestPyPI
just verify-install-testpypi # install from TestPyPI + smoke test
just bump-dry-run # print next semver from unreleased commits
just changelog-dry-run   # preview unreleased section with bumped version
just release-dry-run     # show current/next version + release notes preview
just changelog    # write full CHANGELOG.md from git tags
just version-info # generate build/version_info.txt
just build        # build one-file executable with PyInstaller
just clean        # remove generated artifacts

Usage Overview

Export XML to Excel (xml2excel)

python app/main.py [GLOBAL_OPTIONS] xml2excel --xml PATH_TO_XML --excel OUTPUT_XLSX
Argument Description
--xml Parent file (.pxml, .uxml, or .oxml). Children loaded via <StepRecipeID>.
--excel Destination Excel workbook.

Import Excel to XML (excel2xml)

python app/main.py [GLOBAL_OPTIONS] excel2xml --xml PATH_TO_XML --excel EDITED_XLSX
Argument Description
--xml Same parent file used for export.
--excel Edited Excel workbook.

Global Options

Option Description
--debug Write DEBUG logs to batch_bulk_editor.log.
--no-progress Disable progress bars
--version Show CLI version and exit.
--help Show command help.

Debug Mode

Add --debug before the subcommand to capture detailed logs:

python app/main.py --debug xml2excel --xml myRecipe.pxml --excel out.xlsx
  • Creates/appends batch_bulk_editor.log at DEBUG level.
  • Console logs are rendered with Rich coloring.
  • Repeated warning patterns are summarized in console output while debug file logs remain detailed.

Use --no-progress before the subcommand to control progress bars:

python app/main.py --no-progress excel2xml --xml myRecipe.pxml --excel edits.xlsx

By default, progress bars are enabled only for interactive terminals.


Flow Chart

flowchart LR
  subgraph XML2Excel
    A1([Start]) --> A2{XML exists?}
    A2 -- No --> A3([Error & Exit])
    A2 -- Yes --> A4[Parse parent & children]
    A4 --> A5[Extract nodes → row dicts]
    A5 --> A6[Write Excel workbook]
    A6 --> A7([Done])
  end

  subgraph Excel2XML
    B1([Start]) --> B2{XML exists?}
    B2 -- No --> B3([Error & Exit])
    B2 -- Yes --> B4[Load original XML → RecipeTree]
    B4 --> B5[Read Excel rows]
    B5 --> B6{"Row = existing/new/missing?"}
    B6 -- existing --> B7[update node]
    B6 -- new      --> B8[create node]
    B6 -- missing  --> B9[delete node]
    B7 --> B10[Reorder & write XML]
    B8 --> B10
    B9 --> B10
    B10 --> B11([Done])
  end

  XML2Excel -.-> Excel2XML

Example Excel Output

FullPath TagType Name Real Integer String EnumerationSet EnumerationMember Defer FormulaValueLimit_Verification
TEST/Parameter[XFER5_TARGET_CONC_DB] Parameter XFER5_TARGET_CONC_DB 0
TEST/Steps/Step[ACQ_REL:1]/FormulaValue[X_R_END_PHASE_PROMPT] FormulaValue X_R_END_PHASE_PROMPT N_DISABLEENABLE DISABLE No_Limits
TEST/Steps/Step[ACQ_REL:1]/FormulaValue[X_R_END_TYPE] FormulaValue X_R_END_TYPE N_ENDTYPE AQREL_END_TYPE No_Limits

Example XML Schema Snippet

<xs:element name="Parameter">
  <xs:complexType>
    <xs:sequence>
      <xs:element name="Name" type="xs:string" minOccurs="0"/>
      <xs:element name="ERPAlias" minOccurs="0"/>
      <xs:element name="PLCReference" type="xs:unsignedByte" minOccurs="0"/>
      <xs:element name="Real" type="xs:unsignedShort" minOccurs="0"/>
      <xs:element name="High" type="xs:unsignedShort" minOccurs="0"/>
      <xs:element name="Low" type="xs:unsignedByte" minOccurs="0"/>
      <xs:element name="EngineeringUnits" type="xs:string" minOccurs="0"/>
      <xs:element name="Scale" type="xs:boolean" minOccurs="0"/>
    </xs:sequence>
  </xs:complexType>
</xs:element>

<xs:element name="FormulaValue">
  <xs:complexType>
    <xs:sequence>
      <xs:element name="Name" type="xs:string" minOccurs="0"/>
      <xs:element name="Display" type="xs:boolean" minOccurs="0"/>
      <xs:element name="Value" minOccurs="0"/>
      <xs:element name="Defer" type="xs:string" minOccurs="0"/>
      <xs:element name="Real" type="xs:decimal" minOccurs="0"/>
      <xs:element name="EngineeringUnits" type="xs:string" minOccurs="0"/>
      <xs:element name="FormulaValueLimit" minOccurs="0">
        <xs:complexType>
          <xs:attribute name="Verification" type="xs:string" use="optional"/>
          <xs:sequence>
            <xs:element name="LowValue" type="xs:decimal" minOccurs="0"/>
            <xs:element name="HighValue" type="xs:decimal" minOccurs="0"/>
          </xs:sequence>
        </xs:complexType>
      </xs:element>
    </xs:sequence>
  </xs:complexType>
</xs:element>

Preservation Rules & Edge Cases

  • Empty Tags: If a sub-element existed (even empty), it remains.
  • Create FormulaValueLimit only if FormulaValueLimit_* columns are non-blank or it existed originally.
  • Type Enforcement: Exactly one of Real, Integer, String, or EnumerationSet per row.
  • Defer Validation: A <FormulaValue>’s Defer must match a parameter name in the same sheet.
    • Example output:
[30-May-2025 14:49:35]  ERROR:  CP_GMP_PROCEDURE.PXML!Row924: defer target 'DSTFP_TEMP_PROC2_TEMP_STATE_CMD' not found for CP_GMP_PROCEDURE/Steps/Step[UP_DSTFP_PROCESS:1]/FormulaValue[TEMP_PROC2_TEMP_STATE_CMD]

Troubleshooting

  1. No Sheet Found

    • Sheet name must match the XML filename (TEST.pxml → sheet “TEST.pxml”).
  2. Missing Data-Type

    • Every Parameter or FormulaValue row must have one and only one data-type column.
  3. Need More Logs?

    • Add --debug to capture detailed steps in batch_bulk_editor.log.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

ftbatch_bulk_edit-0.2.6.tar.gz (212.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

ftbatch_bulk_edit-0.2.6-py3-none-any.whl (24.9 kB view details)

Uploaded Python 3

File details

Details for the file ftbatch_bulk_edit-0.2.6.tar.gz.

File metadata

  • Download URL: ftbatch_bulk_edit-0.2.6.tar.gz
  • Upload date:
  • Size: 212.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.10.4 {"installer":{"name":"uv","version":"0.10.4","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Pop!_OS","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for ftbatch_bulk_edit-0.2.6.tar.gz
Algorithm Hash digest
SHA256 74bec1619d909aca9349f042baa8c24d0bb25c08f73dcde9072204ee4f0b3d50
MD5 79e7e1d47de77854ff8baec619d6c238
BLAKE2b-256 f497abc916ccf30d3ad71858709885520321de9addf38022aaab6cd8c309429c

See more details on using hashes here.

File details

Details for the file ftbatch_bulk_edit-0.2.6-py3-none-any.whl.

File metadata

  • Download URL: ftbatch_bulk_edit-0.2.6-py3-none-any.whl
  • Upload date:
  • Size: 24.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.10.4 {"installer":{"name":"uv","version":"0.10.4","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Pop!_OS","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for ftbatch_bulk_edit-0.2.6-py3-none-any.whl
Algorithm Hash digest
SHA256 03290edde9f220f6962a88454d911d136ff1c06ce8758429f4c043a39dd9291e
MD5 d504f61b5f157e24d92baecb20bdad99
BLAKE2b-256 e3be1711289baeba0ee737d2dc4e67d49dfd2a89fedadf980f3bdb784f74d691

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

0.2.6 This release

2 files

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page