From 835dcb8fe5491b957a0a5f1be58081bf61f6ff99 Mon Sep 17 00:00:00 2001 From: Bailey Nguyen Date: Wed, 23 Sep 2026 10:22:33 -0500 Subject: [PATCH] docs(cli): describe buffered XML JSON transcoding accurately --- .agents/skills/polyxml-core-engine/SKILL.md | 2 ++ README.md | 4 +-- crates/polyxml-cli/src/main.rs | 2 +- crates/polyxml-core/src/transcoder.rs | 6 ++-- docs/guides/compiler.md | 4 +-- docs/guides/python.md | 3 +- docs/guides/rust.md | 31 ++++++++++----------- docs/index.md | 2 +- docs/why-polyxml.md | 6 ++-- 9 files changed, 30 insertions(+), 30 deletions(-) diff --git a/.agents/skills/polyxml-core-engine/SKILL.md b/.agents/skills/polyxml-core-engine/SKILL.md index ca52a98d..67c04905 100644 --- a/.agents/skills/polyxml-core-engine/SKILL.md +++ b/.agents/skills/polyxml-core-engine/SKILL.md @@ -26,6 +26,8 @@ This skill documents the high-performance design patterns and strict constraints - Resolve refs leniently like `parser.rs::append_general_ref`: `is_char_ref()`/`resolve_char_ref()` for `&#NN;`/`&#xNN;`, `escape::resolve_xml_entity()` for `amp`/`lt`/`gt`/`quot`/`apos`, else push the raw name (never error — a document the core accepts must not fail in generated code). - Never enable `trim_text` on a reader that assembles split text: per-segment trimming loses spaces around refs (`x & y` → `x&y`). Trim the assembled buffer once at element end (the transcoder `End` arm). - Attribute values arrive raw too — always `escape::unescape` them (`parse_attributes`, the transcoder's Start/Empty attr arms). +5. **Document Transcoding Is Buffered**: + - `transcoder::xml_to_json` and `json_to_xml` accept complete byte slices and return complete byte vectors. The schema-free path constructs a `serde_json::Value` tree; the CLI reads all stdin or file input before calling it. Pipes do not make this API incremental or zero-copy. Keep CLI help and docs distinct from `XmlItemStream` and the Wasm record-stream API. ## 2. Testing & Verification diff --git a/README.md b/README.md index 0309e0eb..6e816c43 100644 --- a/README.md +++ b/README.md @@ -96,9 +96,9 @@ json_bytes = customer.to_json(indent=2) # native JSON on the same model --- -## 🔄 Dual-Format XML ↔ JSON Streaming Transcoder (`polyxml transcode`) +## 🔄 Dual-Format XML ↔ JSON Transcoding (`polyxml transcode`) -Bridge legacy enterprise XML (ISO 20022 banking, HL7 healthcare, FIXM aviation) and modern JSON microservices with an ultra-fast, zero-copy streaming transcoder — via stdin/stdout CLI pipes or the `polyxml.xml_to_json` / `polyxml.json_to_xml` Python APIs. **[Full reference →](docs/guides/compiler.md)** +Bridge legacy enterprise XML (ISO 20022 banking, HL7 healthcare, FIXM aviation) and modern JSON microservices through stdin/stdout CLI pipes or the `polyxml.xml_to_json` / `polyxml.json_to_xml` Python APIs. Each call reads and converts a complete document in memory. **[Full reference →](docs/guides/compiler.md)** --- diff --git a/crates/polyxml-cli/src/main.rs b/crates/polyxml-cli/src/main.rs index 1205967a..633b8d4e 100644 --- a/crates/polyxml-cli/src/main.rs +++ b/crates/polyxml-cli/src/main.rs @@ -43,7 +43,7 @@ pub enum Commands { /// Validate XML schema syntax and structural invariants without generating code Validate(ValidateArgs), - /// Bidirectionally transcode XML ↔ JSON with zero-copy streaming + /// Convert complete XML or JSON documents; stdin/stdout pipes are supported Transcode(TranscodeArgs), /// Print a shell completion script with target-aware option suggestions diff --git a/crates/polyxml-core/src/transcoder.rs b/crates/polyxml-core/src/transcoder.rs index 211dead7..f93b6fdc 100644 --- a/crates/polyxml-core/src/transcoder.rs +++ b/crates/polyxml-core/src/transcoder.rs @@ -16,7 +16,8 @@ use crate::serializer::XmlSerializer; /// /// If a `ModelSchema` is provided, typed data-binding is used, respecting numeric, boolean, /// and collection types as well as field aliases. -/// If `schema` is None, zero-copy dynamic streaming transcoding is used. +/// If `schema` is None, XML events are assembled into a JSON value tree. +/// The complete input and output are held in memory. pub fn xml_to_json( xml: &[u8], schema: Option>, @@ -35,7 +36,8 @@ pub fn xml_to_json( /// /// If a `ModelSchema` is provided, typed data-binding is used, mapping JSON properties to XML /// elements, attributes, and namespaces. -/// If `schema` is None, zero-copy dynamic streaming transcoding is used. +/// If `schema` is None, the complete JSON input is parsed into a value tree +/// before XML output is written into a byte buffer. pub fn json_to_xml( json: &[u8], schema: Option>, diff --git a/docs/guides/compiler.md b/docs/guides/compiler.md index 475b031b..5799d7b1 100644 --- a/docs/guides/compiler.md +++ b/docs/guides/compiler.md @@ -210,13 +210,13 @@ Validates: ### 4. `polyxml transcode` -Bidirectionally transcode between XML and JSON using zero-copy streaming, with optional schema guidance: +Bidirectionally convert complete XML and JSON documents, with optional schema guidance. The command accepts stdin and stdout pipes, but reads the full input and buffers the full output before writing it: ```bash # 1. Transcode XML to JSON with W3C XSD schema typing polyxml transcode --schema order.xsd --pretty order.xml --out order.json -# 2. Stream directly through stdin / stdout pipes +# 2. Connect stdin / stdout pipes cat order.xml | polyxml transcode --schema order.xsd > order.json # 3. Transcode JSON back to XML with specified root element diff --git a/docs/guides/python.md b/docs/guides/python.md index e2b3ee11..c2d89a0e 100644 --- a/docs/guides/python.md +++ b/docs/guides/python.md @@ -457,7 +457,7 @@ user = parser.parse("data.json", User) ## 8. High-Performance XML ↔ JSON Transcoding (`polyxml.xml_to_json` & `polyxml.json_to_xml`) -PolyXML provides zero-copy streaming functions to transcode between XML and JSON directly in Rust/C without building intermediate DOM trees or incurring Python loop overhead. +PolyXML provides Rust-backed functions to convert complete XML and JSON documents without a Python-level parsing loop. Each call holds the input and output in memory; schema-free conversion also builds an intermediate JSON value tree. ### Schema-Directed Transcoding @@ -536,4 +536,3 @@ with open("order.xml", "rb") as f: ``` - diff --git a/docs/guides/rust.md b/docs/guides/rust.md index b13a3b51..0c5af493 100644 --- a/docs/guides/rust.md +++ b/docs/guides/rust.md @@ -306,7 +306,7 @@ To achieve the maximum throughput from `polyxml-core`: --- -## 8. Native JSON Codecs & Streaming Transcoder +## 8. Native JSON Codecs & Document Transcoder ### Inherent JSON Methods on Generated Models @@ -325,34 +325,33 @@ let restored = Order::from_json_str(&json_str)?; let from_bytes = Order::from_json_slice(&json_vec)?; ``` -### Direct Streaming Transcoder (`polyxml::transcoder`) +### Whole-Document Transcoder (`polyxml::transcoder`) -For high-speed transcoding without compiling Rust structs, use `polyxml::transcoder`: +To convert a complete document without compiling Rust structs, use +`polyxml::transcoder`. It accepts byte slices and returns newly allocated +output bytes; schema-free conversion builds an intermediate JSON value tree: ```rust -use polyxml::transcoder::{xml_to_json, json_to_xml, TranscodeOptions}; +use polyxml::transcoder::{xml_to_json, json_to_xml}; let xml_input = br#"Sensor19.99"#; // Transcode XML to JSON with pretty formatting let json_bytes = xml_to_json( xml_input, - None, // Optional Arc or SchemaIR - TranscodeOptions { - pretty: true, - ..Default::default() - }, + None, // Optional Arc + Some(2), // Indentation width + true, // Use schema field aliases )?; -// Transcode JSON back to XML with specified root element +// Transcode JSON back to XML, inferring the root from its single top-level key let restored_xml = json_to_xml( &json_bytes, None, - TranscodeOptions { - root_tag: Some("Product".to_string()), - pretty: true, - ..Default::default() - }, + None, + Some(2), + None, // Namespace handling + None, // Namespace map )?; ``` @@ -392,5 +391,3 @@ let archived = rkyv::access::(&bytes)?; assert_eq!(archived.id, 42); ``` - - diff --git a/docs/index.md b/docs/index.md index b86f49f1..b6b9729d 100644 --- a/docs/index.md +++ b/docs/index.md @@ -58,7 +58,7 @@ Legacy XML Toolchains (JAXB, CodeSynthesis, xsdata, xgen) The PolyXML Way ✅ Unified Rust Tool: Generates idiomatic, type-safe code (like protoc) across 7 languages. ✅ Zero-Allocation Streaming: Direct-to-struct parsing with quick-xml & lexical-core (10x–24x faster). -✅ Dual-Format XML ↔ JSON: Zero-copy streaming transcoder (polyxml transcode) & dual-annotated models. +✅ Dual-Format XML ↔ JSON: Whole-document transcoding (`polyxml transcode`) and dual-annotated models. ✅ Modern Language Idioms: Immutable Java 21+ records, C++20 value types, Python 3.12 PEP 695 dataclasses. ✅ Secure by Design: Pure-Rust streaming parser structurally immune to XXE (CWE-611) & SSRF. ✅ 100% Permissive MIT: Zero commercial licensing fees, zero GPL infection risk. diff --git a/docs/why-polyxml.md b/docs/why-polyxml.md index abfe31d5..73b47516 100644 --- a/docs/why-polyxml.md +++ b/docs/why-polyxml.md @@ -60,7 +60,7 @@ Historical C++ tools like CodeSynthesis XSD and gSOAP enforce strict **GPL v2 / PolyXML is **100% permissively licensed under the MIT License**, with zero runtime licensing fees, zero commercial paywalls, and zero legal restrictions on proprietary distribution. -### 5. Dual-Format Polyglot Architecture & Zero-Copy Streaming Transcoder (`polyxml transcode`) +### 5. Dual-Format Polyglot Architecture & XML/JSON Transcoding (`polyxml transcode`) Enterprise engineering rarely lives in an XML-only silo. Interbank rails (ISO 20022), aviation telemetry (FIXM), and healthcare networks (HL7) mandate strict XML Schema contracts, but modern cloud services, microservices, and frontends operate on JSON. Historically, bridging this divide forced engineering teams into painful trade-offs: @@ -68,7 +68,7 @@ Historically, bridging this divide forced engineering teams into painful trade-o - **Duplicate Schema Maintenance**: Manually writing and synchronizing separate XSD and OpenAPI/JSON schemas across teams inevitably leads to silent drift and catastrophic production outages. PolyXML breaks this dichotomy through a **natively dual-format architecture**: -- **Zero-Copy Streaming Transcoder (`polyxml transcode`)**: A Rust-powered CLI and runtime transcoder that converts XML ↔ JSON bidirectionally via streaming events without building DOM trees. +- **Whole-Document Transcoder (`polyxml transcode`)**: A Rust-powered CLI and runtime converter for XML ↔ JSON. It accepts stdin/stdout pipes, but buffers each complete input and output document; schema-free conversion builds an intermediate JSON value tree. - **Schema-Directed Precision**: Use `--schema schema.xsd` to ensure numeric types, booleans, and arrays in JSON match the exact XSD type definitions rather than ambiguous strings. - **Dynamic Schema-Less Fallback**: Automatically preserves XML attributes (`@attr`) and text content (`#text`) in pure JSON when no schema is present. - **Natively Dual-Annotated Generated Models**: @@ -179,7 +179,7 @@ Across more than 600 official test groups from Sun Microsystems, Microsoft, and | **`xsd-parser` in Rust** | A battle-tested compiler that doesn't panic on complex schemas, with automatic Tarjan `Box` cycle breaks, inherent streaming XML codecs, and native `.to_json_string()` codecs. | | **`xgen` in Go** | Dual `xml:"..."` and `json:"..."` struct tags on every model, true `xs:choice` mutual exclusivity validation, pointer cycle breaks, and canonical Go initialism normalization. | | **`xsd.exe` in .NET** | Modern C# 12 records with primary constructors, dual `XmlSerializer` and `System.Text.Json` attributes (`[JsonPropertyName]`, `[JsonConverter]`), and standard `IValidatableObject` integration. | -| **Ad-hoc XML ↔ JSON Scripts** | Zero-copy streaming CLI (`polyxml transcode`) with schema-directed precision or dynamic `@attr` preservation, executing in microseconds. | +| **Ad-hoc XML ↔ JSON Scripts** | CLI document conversion (`polyxml transcode`) with schema-directed precision or dynamic `@attr` preservation. | **Ready to modernize your XML infrastructure?** 👉 **[Get Started with the 5-Minute Quickstart →](quickstart.md)**