Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/ProwlEngine/Prowl.Echo/llms.txt

Use this file to discover all available pages before exploring further.

Prowl.Echo ships four interop formats — JSON, BSON, YAML, and XML — that let you move data between EchoObject trees and the wider ecosystem of web services, databases, config tooling, and legacy systems. All four are implemented from scratch with no external dependencies, and all four implement IFileFormat, so the full extension method API (WriteToString, ReadFromString, WriteToBytes, ReadFromBytes, WriteToFile, ReadFromFile) is available on every one of them.
The interop formats do not preserve every EchoType distinction. JSON, BSON, and YAML coalesce small integer types to int or double on read-back. XML preserves all types when reading Echo-produced output (via type attributes), but infers types when reading generic XML. If you need a lossless round-trip, use Echo binary or Echo text.

JSON

JsonFileFormat writes clean, standard JSON and reads both Echo-produced JSON and arbitrary JSON documents from external sources. It has no external dependencies and handles all EchoType values, encoding ByteArray as a Base64 string and special floating-point values (NaN, Infinity) as quoted strings.

Writing JSON

using Prowl.Echo;

EchoObject echo = Serializer.Serialize(myObject);

// Write to a JSON string
string json = echo.WriteToJson();

// The output is indented by default:
// {
//   "name": "Aria",
//   "level": 42,
//   "health": 98.5
// }

Compact JSON output

Access the singleton to disable indentation:
JsonFileFormat.Instance.Indented = false;
string compact = JsonFileFormat.Instance.WriteToString(echo);
// {"name":"Aria","level":42,"health":98.5}

Reading JSON

EchoObject.ReadFromJson accepts any valid JSON — not just Echo-produced output — making it suitable for consuming external API responses:
string apiResponse = await httpClient.GetStringAsync("https://api.example.com/data");
EchoObject echo = EchoObject.ReadFromJson(apiResponse);

// Navigate the parsed tree
string name  = echo["name"].StringValue;
int    level = echo["level"].IntValue;

Using IFileFormat extension methods

// Write to a file
JsonFileFormat.Instance.WriteToFile(echo, "output.json");

// Read from a file
EchoObject echo = JsonFileFormat.Instance.ReadFromFile("input.json");

// Write to bytes
byte[] bytes = JsonFileFormat.Instance.WriteToBytes(echo);

// Read from bytes
EchoObject echo = JsonFileFormat.Instance.ReadFromBytes(bytes);
When reading generic JSON, numbers without a decimal point are parsed as int, long, or ulong (in that order of preference). Numbers with a decimal point or exponent are parsed as double. The original EchoType.Byte, EchoType.Short, and EchoType.Float distinctions are not recoverable from standard JSON.

BSON

BsonFileFormat implements the BSON specification without any external dependencies. BSON is the native wire format for MongoDB and is well supported by drivers across many languages. The format produces a byte[] and reads from a byte[], making it a natural fit for binary-oriented pipelines.

Writing BSON

EchoObject echo = Serializer.Serialize(myDocument);

// Write to a byte array
byte[] bson = echo.WriteToBson();

Reading BSON

byte[] bson = await FetchBsonFromDatabase();
EchoObject echo = EchoObject.ReadFromBson(bson);

Using IFileFormat extension methods

// Write to a file
BsonFileFormat.Instance.WriteToFile(echo, "document.bson");

// Read from a file
EchoObject echo = BsonFileFormat.Instance.ReadFromFile("document.bson");

// Write to / read from a Stream directly
BsonFileFormat.Instance.WriteTo(echo, networkStream);
EchoObject echo = BsonFileFormat.Instance.ReadFrom(networkStream);

Type mapping notes

BSON has a smaller set of numeric types than EchoType. The mapping applied during write is:
EchoTypeBSON type
Byte, sByte, Short, UShort, IntInt32
UInt, LongInt64
ULongInt64 (reinterpreted as signed)
Float, DoubleDouble
DecimalString (preserves precision)
ByteArrayBinary (generic subtype)
BoolBoolean
NullNull
ListArray
CompoundDocument
BSON requires a document at the top level. If you write an EchoObject that is not a Compound, it is automatically wrapped in a single-key document during write and unwrapped on read.

YAML

YamlFileFormat produces clean, indented YAML and reads both Echo-produced YAML and generic YAML documents. It supports mappings, sequences, scalars (strings, numbers, booleans, null), inline flow-style notation, and the !!binary tag for ByteArray values.

Writing YAML

EchoObject echo = Serializer.Serialize(myConfig);

string yaml = echo.WriteToYaml();

// Output example:
// name: "Aria"
// level: 42
// health: 98.5
// tags:
//   - "warrior"
//   - "ranger"

Reading YAML

EchoObject.ReadFromYaml accepts any valid YAML, including documents you did not produce with Prowl.Echo:
string configFile = File.ReadAllText("config.yaml");
EchoObject echo = EchoObject.ReadFromYaml(configFile);

Using IFileFormat extension methods

// Write to a file
YamlFileFormat.Instance.WriteToFile(echo, "config.yaml");

// Read from a file
EchoObject echo = YamlFileFormat.Instance.ReadFromFile("config.yaml");

Type mapping notes

YAML scalars are parsed in this order: null keywords → boolean keywords → intlongdouble → plain string. YAML special float values (.nan, .inf, -.inf) map to EchoType.Double. The !!binary tag maps to EchoType.ByteArray via Base64 decoding.

XML

XmlFileFormat produces standard XML 1.0 with type attributes that carry the full EchoType name. When you read Echo-produced XML back, all type information is restored exactly. It also reads generic XML that has no type attributes, inferring types by parsing the text content — useful for importing data from external XML sources.

Writing XML

EchoObject echo = Serializer.Serialize(myObject);

string xml = echo.WriteToXml();
The output includes an XML declaration and type attributes on every element:
<?xml version="1.0" encoding="utf-8"?>
<echo type="compound">
  <name type="string">Aria</name>
  <level type="int">42</level>
  <health type="float">98.5</health>
  <active type="bool">true</active>
</echo>

Reading XML

EchoObject.ReadFromXml accepts both Echo-produced XML (with type attributes) and generic XML from external systems:
// Read Echo-produced XML (full type fidelity)
string xml = File.ReadAllText("data.xml");
EchoObject echo = EchoObject.ReadFromXml(xml);

// Read generic XML from an external source
string externalXml = await httpClient.GetStringAsync("https://api.example.com/data.xml");
EchoObject echo = EchoObject.ReadFromXml(externalXml);
// Types are inferred: integers → int/long, decimals → double, rest → string

Using IFileFormat extension methods

// Write to a file
XmlFileFormat.Instance.WriteToFile(echo, "export.xml");

// Read from a file
EchoObject echo = XmlFileFormat.Instance.ReadFromFile("import.xml");

XML element name sanitization

XML element names must start with a letter or underscore and may only contain letters, digits, _, -, and .. If a compound key does not satisfy these rules, XmlFileFormat sanitizes the element name and stores the original key in a key attribute so it is recovered faithfully on read:
<!-- Key "$type" becomes "_type" element with key attribute -->
<_type key="$type" type="string">MyNamespace.MyClass</_type>

Importing external documents

All four interop format readers can parse documents they did not produce. This makes it straightforward to pull data from external APIs or configuration systems into an EchoObject for processing with Echo’s serialization pipeline.
// Import a REST API JSON response
string json = await httpClient.GetStringAsync("https://api.example.com/players/1");
EchoObject player = EchoObject.ReadFromJson(json);

// Import a YAML configuration file from a third-party tool
EchoObject toolConfig = EchoObject.ReadFromYaml(
    File.ReadAllText("third-party-config.yaml")
);

// Import a legacy XML export
EchoObject legacyData = EchoObject.ReadFromXml(
    File.ReadAllText("legacy-export.xml")
);

// Deserialize directly into your .NET type once imported
MyPlayer result = Serializer.Deserialize<MyPlayer>(player);
When reading generic JSON, YAML, or untyped XML, the EchoObject tree uses the broadest compatible type (e.g., int instead of byte, double instead of float). If your deserialization target type uses narrower types, the Serializer will coerce them automatically during Deserialize.

Build docs developers (and LLMs) love