namespace2xml 3.0.0

dotnet tool install --global namespace2xml --version 3.0.0
                    
This package contains a .NET tool you can call from the shell/command line.
dotnet new tool-manifest
                    
if you are setting up this repo
dotnet tool install --local namespace2xml --version 3.0.0
                    
This package contains a .NET tool you can call from the shell/command line.
#tool dotnet:?package=namespace2xml&version=3.0.0
                    
nuke :add-package namespace2xml --version 3.0.0
                    

namespace2xml

NuGet Ansible Galaxy CI

A deterministic configuration transformer. It reads ordered namespace profiles and structured inputs, applies scheme directives, and renders many outputs from one overlaid model — XML, JSON, YAML, INI, namespace profiles and quoted-namespace files.

Identical inputs always produce byte-identical outputs, on every supported platform, in every locale, on every run.


Version 3.0 is a rewrite

3.0 replaces the 2.x implementation entirely, against a specification written before the code. The specification is the contract; the implementation is an attempt to satisfy it. Behaviour that 2.4.0 left undefined is now defined, and the intentional differences are listed in docs/migration-2.x-to-3.0.md.

3.0.0 is the permanent release of that contract. See KNOWN-LIMITS.md for the deliberate boundaries of 3.0 and the contract work deferred to 3.1.


Install

dotnet tool install --global namespace2xml

The tool requires the .NET 10 SDK. On .NET 8, installation can misleadingly report that DotnetToolSettings.xml is missing and call the package invalid; install the .NET 10 SDK and retry.

To use it from Ansible, add the stop_cran.namespace2xml collection. The filter evaluates on the controller, which is where the tool is needed; target nodes need neither .NET nor the tool:

ansible-galaxy collection install stop_cran.namespace2xml

See ansible/README.md for arguments, memoization and the fidelity limits of the data-to-profile mapping.

Basic usage

namespace2xml -i <input files> -s <scheme files> [-o <output directory>]

Input files carry the data. Scheme files describe what to produce from it: which output formats, which parts become XML elements or attributes, which keys are hidden, and so on.

One model, many formats

test.properties:

a.b.x=1

scheme.properties:

a.output=xml,json,yaml,ini,namespace
namespace2xml -i test.properties -s scheme.properties

produces a.xml, a.json, a.yaml, a.ini and a.properties:

<?xml version="1.0" encoding="utf-8"?>
<b>
  <x>1</x>
</b>
{
  "b": {
    "x": 1
  }
}
b:
  x: 1
[b]
x=1
b.x=1

The output selector a names what to render, and Section 16.3 removes it before rendering, so b is what each document contains. Add root to wrap the result in a name of your choosing.

Scalars become elements in XML unless a scheme directive asks otherwise. Section 16.6 makes attributes an explicit opt-in, and the choice is scoped to the formats that have attributes:

a.output=xml,json
a.b.x.type=attribute

renders <b x="1" /> in XML while JSON keeps "x": 1 as an ordinary member.

Overlaying

Inputs are applied in command-line order, and later files win:

namespace2xml -i base.properties -i production.properties -i secrets.properties -s scheme.properties

Layer by lifetime — base, then environment, then instance, then secrets — not by topic. See docs/usage-methodology.md for why, and for the anti-patterns that follow from getting it backwards.

Reading XML that was formatted for humans

Indented XML holds whitespace-only text between element children, and the default xmlinputoptions=PreserveWhitespace keeps every text node. Those become content components, so

<r>
  <b>1</b>
</r>

is the model r.#0, r.#1.b, r.#2 — and not r.b. Nothing warns about this: an override written r.b=2 becomes a new node beside r.#1.b rather than a replacement of it, and the run still exits 0.

When the input was formatted for a human to read, ask for the compatibility mode:

xmlinputoptions=NormalizeFormattingWhitespace

It discards whitespace-only text between element children, which makes those elements addressable by name, and warns once per document (WARN007) because specification Section 11.7 says discarding that text weakens the same-format round-trip guarantee. That trade is the reason it is opt-in: preserving every byte is what makes an unmodified round trip byte-identical, and only you know whether the file you are reading is data or layout.

docs/format-xml.md covers the whitespace modes in full, and docs/usage-methodology.md works through the override that this defeats.


For automation and AI agents

This tool is designed to be used by programs, and to be argued with by them.

  • --diagnostics-format json writes the entire diagnostic stream to standard error as one canonical JSON array conforming to spec/diagnostic-stream.schema.json. Operational log messages are suppressed in that mode, so standard error is pure data. The array is written once, at exit, so it is always complete and always well-formed.
  • Every diagnostic carries a stable code and a specification anchor naming the clause it enforces, so a disagreement can be reported precisely rather than described. See docs/diagnostics.md.
  • --version prints one <field>: <value> line per field, including the contract-bundle revision that identifies exactly which specification and diagnostic registry the binary implements.
  • --fail-on-warning makes warning-free output an atomic publication policy. If any warning is emitted, the tool completes serialization, preserves the original diagnostic stream, exits 1, and publishes no file. Diagnostic verbosity cannot bypass the policy. This includes WARN007 when XML formatting whitespace is normalized.
  • Exit codes are contractual. 0 is success, including success with warnings by default; 1 is failure or a --fail-on-warning publication refusal. Specification Section 6.3 fixes those two and no others.
  • The specification ships inside the package, so an agent can read the contract offline.
  • Symbols and source link are published alongside every release, so a stack trace resolves to the exact source that produced it.
  • An Ansible collection wraps all of the above for playbook authors, and keeps the guarantees: diagnostics reach the caller unchanged, and a binary that reports no contract-bundle is refused rather than used. stop_cran.namespace2xml ships two plugins — a render filter that renders play variables on the controller, and a render module that renders a managed node's own files in place, idempotently. ansible-doc -t filter and -t module on stop_cran.namespace2xml.render are their argument references.

Start at AGENTS.md. The machine-readable index is llms.txt.


Documentation

These links are relative, so they resolve in a clone and inside the extracted NuGet package, which mirrors this layout. On nuget.org relative links are stripped and will not be clickable: browse the same documents at https://github.com/stop-cran/namespace2xml, or run namespace2xml --version, which prints release-pinned URLs for the specification, the diagnostics registry, llms.txt and the issue tracker.

File What it is
docs/specification.md The contract. Normative and self-contained.
docs/diagnostics.md Every diagnostic code, its meaning and its anchor.
docs/usage-methodology.md When to use this tool, how to layer, how to specialize a document you did not write, what not to do.
docs/format-namespace.md The namespace profile: syntax, escapes, comments, references.
docs/format-json.md JSON input and output, scalar kinds, the numeric-map trap.
docs/format-yaml.md YAML input and output, the RestrictedYaml1 subset.
docs/format-xml.md XML input and output, typed components, CDATA, comments.
docs/format-ini.md INI output, the two-level projection, PortableIni1.
docs/migration-2.x-to-3.0.md Every intentional behaviour change from 2.4.0.
CONTRIBUTING.md The change protocol and the feedback forms.
KNOWN-LIMITS.md What is deliberately not covered yet.
ansible/README.md The stop_cran.namespace2xml Ansible collection: the render filter and the render module, which one to pick, their arguments, and the filter's fidelity limits.
AGENTS.md Entry point for automated agents.

Found a problem?

Good — the project is built to absorb field evidence and evolve without guessing.

Before filing, ask one question: what would have to change so this never surprises anyone again?

Answer File this
The code should have matched the specification Bug report
The specification does not say, or says two things Specification ambiguity
Both are right; I could not find out how to do this Usage gap
The tool cannot express this at all Feature request

Always include the contract-bundle revision from --version. A report against an unknown contract revision cannot be acted on. Set the Component field to say which surface you were using — the CLI or the Ansible collection — and for the collection add ansible --version and the collection version.

Full guidance, including the report form and the rules for agent-authored reports, is in CONTRIBUTING.md.

If the four links above are not clickable, you are reading a copy with relative links stripped — open https://github.com/stop-cran/namespace2xml/issues/new/choose and pick the form there.


Building from source

dotnet build namespace2xml.slnx
dotnet test  namespace2xml.slnx

Requires the .NET 10 SDK. The solution uses the .slnx format.

License

Apache-2.0.

Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

This package has no dependencies.

Version Downloads Last Updated
3.0.0 48 9/12/2026
3.0.0-preview.5 82 8/21/2026
3.0.0-preview.4 108 8/14/2026
3.0.0-preview.3 81 8/11/2026
3.0.0-preview.2 66 8/9/2026
3.0.0-preview.1 73 8/6/2026
2.4.0 406 9/6/2025
2.3.0 223 4/8/2025
2.2.1 238 8/8/2024
2.1.3 346 8/18/2023
2.1.2 263 6/8/2023
2.1.1 267 5/12/2023
2.1.0 358 3/16/2023
2.1.0-rc4 256 3/15/2023
2.1.0-rc3 230 3/15/2023
2.1.0-rc2 303 3/6/2023
2.1.0-rc1 307 2/4/2023
2.1.0-rc0 309 1/15/2023
2.0.4 786 8/4/2020
2.0.3 587 8/4/2020
Loading failed

Stable 3.0 specification-first rewrite with deterministic multi-format output, machine-readable diagnostics, and a complete offline contract. See CHANGELOG.md.