Skip to content

crowbait/xmlmath

Repository files navigation

XMLMath

Latest Release License Tests

XMLMath is a command-line tool for performing arithmetic operations directly on XML files. It allows batch modifications of attributes and values using a flexible set of filters and modifiers, allowing automated XML numeric data transformations.

Features

  • Run arbitrary (awk-compatible) mathematic operations on attribute or element values
  • Target elements or attributes via tag names, or additional regex
  • Clamp and/or round results
  • Modify files in-place or output changes to a file or stdout
  • Optionally diff changes to stdout or a file
  • Small dependency footprint

What this is not

  • Fast. It really isn't.
  • Suitable for non-math operations. You'll be better off with regex-based find-replace in any text editor.

Contents

Getting Started

Requirements

XMLMath relies on awk, sed, diff and xmllint. With the exception of xmllint, these are already included in many distributions. On Debian-/Ubuntu-based distros, xmllint can be installed with:

sudo apt install libxml2-utils

Download

Download the built version of XMLMath from the latest release. You could put it somewhere that's in your PATH to make it available globally.

curl -L -o xmlmath https://github.com/crowbait/xmlmath/releases/latest/download/xmlmath
chmod +x xmlmath

You can also run it directly; this ensures you're always working with the latest release and doesn't put the script file on your drive.

curl -sL https://github.com/crowbait/xmlmath/releases/latest/download/xmlmath | bash -s -- "parameter1" "parameter2" "..."

You'll need to supply all parameters in quotes.

Usage

Syntax:

./xmlmath <attr|value> <operation> <modifier> [options] <...targets>

Examples

This multiplies the value (between tags) of all XML elements named "someval" or "otherval" in input.xml by 2, writing the results back to the same file:

./xmlmath value multiply 2 --file input.xml --inplace someval otherval

This multiplies the value all attributes in the file in.xml with names matching the regex .*someattr AND which are attributes of a tag "tagname" by 1.1, rounding the results to the neares integer and ensuring they are always greater than or equal to 2:

./xmlmath attr multiply 1.1 --int --min 2 --file in.xml --regex -w tagname '.*someattr'

You can run arbitrary operations on the found values, providing they can be expressed in awk-compatible syntax - in this case, all attribute values (see regex) will be replaced with their root added to their squared value. The token x will be substituted for the found value:

./xmlmath attr expression 'sqrt(x)+x*x' --file in.xml -r '.*'

You can get more examples from the tests: test.sh list commands. The index names of those commands correspond to files in test/, which contain the transformed output when running these commands on test/_expectation-template.xml.

Operations

Operation Short Description
add a Add the modifier to the found values
subtract s Subtract the modifier from the found values
multiply m Multiply the found values with the modifier
divide d Divide the found values by the modifier
set Set the found values to the modifier
expression e Treat the modifier as an expression; must be awk-compatible syntax and should be (single-)quoted

Options

Option Short Arg Description
--file -f Path Specifies a file to be used as input. If not given, input is taken from stdin.
requires -f
--inplace
-p Writes the output back to the same file used as input.
--out -o Path Writes the output to Path. Cannot be used with --inplace.
--int -i Rounds results to the nearest integer.
--min Number Clamps all operation results to a minimum value of Number.
--max Number Clamps all operation results to a maximum value of Number.
--regex -r Treats all targets (the list of attribute or value identifiers) as regex patterns instead of exact matches. You should quote each entry; see examples.
--within -w Tag For attr: only matches attributes within the tag Tag.
For val: only matches values that are a child element of Tag - within any depth.
requires -w
--within-additional
--wa Regex Only accepts a match on --within if that line (containing the tag) also satisfies Regex.
--diff -d Displays changes after all operations have finished.
requires -d
--diff-line-length
--dl Number Limits the length of lines in --diff's output to Number, truncating as needed.
requires -d
--diff-file
--df Path Writes diff to a file instead of stdout.
--verbose -v Prints detailed information about what's happening. This WILL make your stdout unusable as XML.
--progress Prints progress information. Prints to stderr, so the stdout should not be affected. Cannot be used with -v.

Development

The main script is modularized and sources its modules, which are in parts/*. This is done for maintainability and is mostly personal preference. It can be run directly in its development form or can be "compiled" by injecting the external modules into the script. This is done by build.sh and writes a complete, self-contained file to build/xmlmath.

Testing is done using test.sh. Within that script, there is an array, mapping a "test-id" to a command to run against the main script. The input for that test run is the file test/test.xml, which is intentionally ill-formatted. There must be a file test/[test-id].xml, which represents the expected output of the run. New test-target-XMLs should be created from test/_expectation-template.xml (same content as test.xml, but well formatted).

About

Math batch operations on XML documents

Topics

Resources

License

Code of conduct

Stars

Watchers

Forks

Sponsor this project

Languages