Yaplon is a versatile command-line tool for converting between various common structured data formats: JSON, YAML, Property Lists (PLIST, both binary and XML), XML, and CSV (read-only for CSV input). It's designed for developers, data analysts, system administrators, or anyone who needs to quickly and easily transform data from one format to another.
In a world of diverse applications and services, data often needs to be exchanged and processed in different formats. Yaplon simplifies this by providing:
- Unified Interface: A single tool to handle multiple conversion types, reducing the need to learn and install separate utilities for each pair of formats.
- Command-Line Power: Easily integrate Yaplon into your scripts and workflows using standard input/output piping.
- Flexibility: Options to sort data (e.g., dictionary keys) before conversion for consistent output, and to minify the output for space efficiency.
- Format-Specific Features: Handles nuances like JSON with comments, binary data in Plists and YAML, different XML structuring approaches, and various CSV dialects.
- Python 3.9+: Modern Python codebase.
Install the latest stable release from the Python Package Index (PyPI):
pip3 install --user --upgrade yaplonDownload pre-built binaries for your platform from the releases page:
- Linux:
yaplon-{version}-linux-x64 - Windows:
yaplon-{version}-windows-x64.exe - macOS:
yaplon-{version}-macos-x64
Make the binary executable and add it to your PATH.
To install the latest development version directly from GitHub:
pip3 install --user --upgrade git+https://github.com/twardoch/yaplonIf you want to contribute to Yaplon or modify it:
- Clone the repository:
git clone https://github.com/twardoch/yaplon.git cd yaplon - Install development dependencies:
This installs the package in editable mode with all development dependencies.
make install-dev
For detailed build and development instructions, see BUILD.md. For GitHub Actions setup, see GITHUB_SETUP.md.
Yaplon can be invoked using the main yaplon command followed by a conversion subcommand (e.g., j2y for JSON to YAML), or by using dedicated shortcut scripts (e.g., json22yaml).
yaplon <command> -i <input_file> -o <output_file> [options]<command>: Specifies the conversion type (see "Conversion Commands" below).-i <input_file>: Input file. If omitted or specified as-, Yaplon reads from standard input (stdin).-o <output_file>: Output file. If omitted or specified as-, Yaplon writes to standard output (stdout). This allows for easy piping.
The following commands define the input and output formats:
c2j: CSV to JSONc2p: CSV to PLISTc2x: CSV to XMLc2y: CSV to YAMLj2p: JSON to PLISTj2x: JSON to XMLj2y: JSON to YAMLp2j: PLIST to JSONp2x: PLIST to XMLp2y: PLIST to YAMLx2j: XML to JSONx2p: XML to PLISTx2y: XML to YAMLy2j: YAML to JSONy2p: YAML to PLISTy2x: YAML to XML
Yaplon supports JSON input with C-style comments (// ... and /* ... */) and trailing commas in objects/arrays (similar to JSON5).
These options are available for most conversion commands:
-i <input_file>, --in <input_file>: Specify the input file. Defaults to stdin.-o <output_file>, --out <output_file>: Specify the output file. Defaults to stdout.-s, --sort: Sort data before conversion. For dictionaries/maps, keys are sorted alphabetically. This helps in producing consistent output, especially for version control.-m, --mini: Minify output. The specific effect depends on the format (e.g., no indents or newlines in JSON/XML, flow style in YAML).
- For
*2p(to Plist):-b, --bin: Output a binary Plist file. By default, an XML Plist is generated.
- For
p2j,y2j(from Plist/YAML to JSON):-b, --bin: Preserve binary data (e.g., from Plist<data>or YAML!!binary) as a simple base64 encoded string in JSON. The default behavior is to represent binary data as a special dictionary:{"__bytes__": true, "base64": "..."}.
- For
*2x(to XML):-R <name>, --root <name>: Specify the root tag name for the XML document. This is particularly useful if the input data is a list or if you want to override the default root tag (which is often 'root' or derived from a single top-level key). This option uses thexmltodictbackend for XML generation.-t <name>, --tag <name>: Wrap the entire output in the specified tag. This option uses thedict2xmlbackend, which may produce a simpler XML structure, especially for lists. If-tis used, the-Roption is ignored.
- For
x2*(from XML):-N, --namespaces: Process XML namespaces. If enabled, tag names in the resulting data structure will include namespace prefixes.
- For
c2*(from CSV):-H, --header: Treat the first row of the CSV as a header row. The CSV data will be read as a list of dictionaries (where keys are header names) instead of a list of lists.-d <dialect>, --dialect <dialect>: Specify the CSV dialect (e.g., 'excel', 'excel-tab', 'unix'). If not specified, Yaplon attempts to sniff the dialect.-k <key_index>, --key <key_index>: (Requires-Hor implies it) Use the values from the column specified bykey_index(a 1-based integer) as keys for a top-level dictionary. The values of this dictionary will be the row dictionaries (with the key column itself removed from the row dictionary).
For convenience, Yaplon also installs shortcut scripts that correspond directly to the conversion commands:
csv22json,csv22plist,csv22xml,csv22yamljson22plist,json22xml,json22yamlplist22json,plist22xml,plist22yamlxml22json,xml22plist,xml22yamlyaml22json,yaml22plist,yaml22xml
Note: These scripts use 22 (e.g., json22yaml) instead of 2 to avoid potential conflicts with other similarly named conversion tools you might have installed.
JSON to YAML (file to file using dedicated tool):
json22yaml -i input.json -o output.yamlJSON to YAML (using pipes and main yaplon command):
cat input.json | yaplon j2y > output.yamlPLIST to JSON (minified, preserving binary as base64 strings):
yaplon p2j -m -b -i input.plist -o output.jsonCSV with header to XML (using a specific column as key and custom root tag):
yaplon c2x -H -k 1 --root "Entries" -i data.csv > data.xmlThis section describes the internal workings of Yaplon.
Yaplon's conversion process generally follows these steps:
- Input: Data is read from an input file or stdin.
- Parsing (
reader.py): The input data is parsed into a standardized Python data structure, primarily usingcollections.OrderedDict. This preserves key order from the source format where applicable.- The
reader.sort_ordereddictfunction can be invoked via the-s/--sortCLI option to recursively sort theseOrderedDicts by key.
- The
- Serialization (
writer.py): The PythonOrderedDictobject is then serialized into the target output format. - Output: The resulting data is written to an output file or stdout.
The Command Line Interface (CLI) is built using the Click library.
- JSON:
- Reading: Handled by
yaplon.ojson.read_json. This module supports JSON5-like features such as C-style comments (//,/* */) and trailing commas. These are stripped byyaplon.file_strip.json.sanitize_jsonbefore parsing with Python's standardjsonmodule (usingobject_pairs_hook=OrderedDict). - Writing: Handled by
yaplon.ojson.json_dump. Can produce regular or minified JSON. Binary data is handled based on the-bflag (see "Binary Data Representation" below).
- Reading: Handled by
- PLIST (Property List):
- Reading: Handled by
yaplon.oplist.read_plist, which wraps Python's standardplistlib. It parses both XML and binary Plists. Plist<data>elements are converted to Pythonbytesobjects, and<date>elements becomedatetime.datetimeobjects. - Writing: Handled by
yaplon.oplist.plist_dumps(for XML Plist) andyaplon.oplist.plist_binary_dumps(for binary Plist, via-bflag). These also useplistlib.
- Reading: Handled by
- YAML:
- Reading: Handled by
yaplon.oyaml.read_yaml, which uses the PyYAML library. It employs custom constructors to load YAML!!binarytags into Pythonbytesobjects and!!timestamptags intodatetime.datetimeobjects. Data is loaded intoOrderedDictto preserve order. - Writing: Handled by
yaplon.oyaml.yaml_dumps. Uses a custom dumper forOrderedDictto maintain key order and forbytesto serialize them as!!binarytags. Supports minified (flow style) output with the-mflag.
- Reading: Handled by
- XML:
- Reading: Handled by
yaplon.reader.xml, which uses the xmltodict library to parse XML into anOrderedDict. Namespace processing can be enabled with the-Nflag. - Writing: Handled by
yaplon.writer.xml. This function is noted as potentially "primitive and buggy" for complex cases. It can use two different backends:xmltodict.unparse: Used by default or when the-R/--rootoption is specified. This backend is generally more feature-rich for representing complex data structures.dict2xml.Converter: Used when the-t/--tagoption is specified. This backend might produce simpler XML, especially for lists, and wraps the entire structure in a single user-defined tag.- Before writing, Python
bytesare converted to base64 encoded strings, anddatetime.datetimeobjects are converted to ISO 8601 strings.
- Reading: Handled by
- CSV:
- Reading: Handled by
yaplon.reader.csvusing Python's standardcsvmodule.- Can read as a list of lists or, if
-H/--headeris used, a list ofOrderedDicts. - Supports dialect sniffing or explicit dialect specification (
-d). - The
-k/--keyoption allows restructuring the data into a top-levelOrderedDictkeyed by values from a specified column.
- Can read as a list of lists or, if
- Writing: CSV writing is not currently supported. Yaplon is read-only for CSV input.
- Reading: Handled by
- Internal Structure:
collections.OrderedDictis used as the primary internal data structure after parsing to ensure that key order from formats like YAML or sorted JSON is preserved and can be maintained in the output. - Binary Data:
- In Python: Represented as
bytesobjects. - PLIST: Native
<data>tags. - YAML:
!!binarytag. - JSON Output:
- Default:
{"__bytes__": true, "base64": "..."}(a dictionary indicating binary content). - With
-bflag (forp2j,y2j): A simple base64 encoded string.
- Default:
- XML Output: Base64 encoded string content within tags.
- In Python: Represented as
While not a formalized plugin system, adding support for a new format would conceptually involve:
- Creating new reader and writer functions in
yaplon/reader.pyandyaplon/writer.pyrespectively. - The reader should parse the new format into an
OrderedDict(or list ofOrderedDicts, etc.). - The writer should take an
OrderedDictand serialize it to the new format. - Adding corresponding CLI commands and options in
yaplon/__main__.py. - Writing comprehensive tests for the new conversions.
Contributions to Yaplon are welcome! Whether it's bug reports, feature suggestions, documentation improvements, or code contributions, your help is appreciated.
Please refer to the "Installation > For Development" section above for instructions on how to clone the repository and set up a development environment.
- Fork the repository on GitHub.
- Create a new branch for your feature or bug fix:
git checkout -b my-feature-branch. - Set up development environment:
make install-dev
- Make your changes.
- Write tests for your changes in the
tests/directory. - Run development workflow:
make dev # format + lint + test-fast - Run full test suite:
make test - Commit your changes with a clear and descriptive commit message.
- Push your branch to your fork:
git push origin my-feature-branch. - Open a Pull Request against the
masterbranch of thetwardoch/yaplonrepository.
The project uses a modern build system with automated testing and releases:
- Local Development:
make devfor quick development workflow - Testing:
make testfor full test suite,make test-fastfor quick tests - Building:
make buildfor packages,make build-binaryfor binaries - Releasing:
python scripts/release.py --bump patch --message "msg"
For detailed information, see BUILD.md and USAGE.md.
- Please report bugs or suggest features by opening an issue on the GitHub Issues page.
- Check the
TODO.mdfile in the repository for a list of known tasks and planned enhancements.
For significant changes, please add an entry to the CHANGELOG.md file, describing the change and referencing the relevant issue or PR if applicable.
Yaplon uses Black for code formatting and Flake8 for linting. Please ensure your contributions adhere to these standards by running make format and make lint.
The project uses pytest for testing. New features should include corresponding tests, and bug fixes should ideally include a test that demonstrates the bug and verifies the fix.
See CHANGELOG.md for a history of changes to the project.
Yaplon is distributed under the MIT License.
- Copyright (c) 2021-2024 Adam Twardoch adam+github@twardoch.com & Jules (AI Agent)
- Copyright (c) 2012-2015 Isaac Muse isaacmuse@gmail.com
- Based on Serialized Data Converter for Sublime Text
- Project Homepage: https://twardoch.github.io/yaplon/
- Python Package on PyPI: https://pypi.org/project/yaplon/
- Source on GitHub: https://github.com/twardoch/yaplon
- Donate: Support the project via PayPal or GitHub Sponsors. (Check
.github/FUNDING.yml)