polyxml 0.1.0__tar.gz → 0.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (28) hide show
  1. {polyxml-0.1.0 → polyxml-0.2.0}/Cargo.lock +268 -6
  2. {polyxml-0.1.0 → polyxml-0.2.0}/Cargo.toml +1 -1
  3. {polyxml-0.1.0 → polyxml-0.2.0}/PKG-INFO +2 -1
  4. {polyxml-0.1.0 → polyxml-0.2.0}/crates/polyxml-core/Cargo.toml +6 -0
  5. polyxml-0.2.0/crates/polyxml-core/README.md +134 -0
  6. polyxml-0.2.0/crates/polyxml-core/benches/core_benchmarks.rs +162 -0
  7. {polyxml-0.1.0 → polyxml-0.2.0}/crates/polyxml-core/src/lib.rs +55 -1
  8. polyxml-0.2.0/crates/polyxml-core/src/parser.rs +393 -0
  9. polyxml-0.2.0/crates/polyxml-core/src/serializer.rs +189 -0
  10. polyxml-0.2.0/crates/polyxml-python/src/lib.rs +799 -0
  11. polyxml-0.2.0/crates/polyxml-python/tests/test_polyxml.py +272 -0
  12. {polyxml-0.1.0 → polyxml-0.2.0}/pyproject.toml +24 -1
  13. polyxml-0.2.0/python/polyxml/__init__.py +87 -0
  14. polyxml-0.1.0/crates/polyxml-core/src/parser.rs +0 -319
  15. polyxml-0.1.0/crates/polyxml-core/src/serializer.rs +0 -175
  16. polyxml-0.1.0/crates/polyxml-python/src/lib.rs +0 -389
  17. polyxml-0.1.0/crates/polyxml-python/tests/test_polyxml.py +0 -98
  18. polyxml-0.1.0/python/polyxml/__init__.py +0 -44
  19. {polyxml-0.1.0 → polyxml-0.2.0}/README.md +0 -0
  20. {polyxml-0.1.0 → polyxml-0.2.0}/crates/polyxml-core/src/converters.rs +0 -0
  21. {polyxml-0.1.0 → polyxml-0.2.0}/crates/polyxml-core/src/error.rs +0 -0
  22. {polyxml-0.1.0 → polyxml-0.2.0}/crates/polyxml-core/src/schema.rs +0 -0
  23. {polyxml-0.1.0 → polyxml-0.2.0}/crates/polyxml-core/src/value.rs +0 -0
  24. {polyxml-0.1.0 → polyxml-0.2.0}/crates/polyxml-core/tests/test_core.rs +0 -0
  25. {polyxml-0.1.0 → polyxml-0.2.0}/crates/polyxml-core/tests/test_security.rs +0 -0
  26. {polyxml-0.1.0 → polyxml-0.2.0}/crates/polyxml-python/Cargo.toml +1 -1
  27. {polyxml-0.1.0 → polyxml-0.2.0}/crates/polyxml-python/README.md +0 -0
  28. {polyxml-0.1.0 → polyxml-0.2.0}/python/polyxml/py.typed +0 -0
@@ -11,6 +11,18 @@ dependencies = [
11
11
  "memchr",
12
12
  ]
13
13
 
14
+ [[package]]
15
+ name = "anes"
16
+ version = "0.1.6"
17
+ source = "registry+https://github.com/rust-lang/crates.io-index"
18
+ checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299"
19
+
20
+ [[package]]
21
+ name = "anstyle"
22
+ version = "1.0.14"
23
+ source = "registry+https://github.com/rust-lang/crates.io-index"
24
+ checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000"
25
+
14
26
  [[package]]
15
27
  name = "autocfg"
16
28
  version = "1.5.1"
@@ -19,9 +31,15 @@ checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53"
19
31
 
20
32
  [[package]]
21
33
  name = "bitflags"
22
- version = "2.13.1"
34
+ version = "2.13.2"
35
+ source = "registry+https://github.com/rust-lang/crates.io-index"
36
+ checksum = "3ded4057c258ba199e2d26386d3af3780957ecaee6c4ef4041c6b4b8b97c0b06"
37
+
38
+ [[package]]
39
+ name = "cast"
40
+ version = "0.3.0"
23
41
  source = "registry+https://github.com/rust-lang/crates.io-index"
24
- checksum = "b588b76d00fde79687d7646a9b5bdf3cc0f655e0bbd080335a95d7e96f3587da"
42
+ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5"
25
43
 
26
44
  [[package]]
27
45
  name = "cfg-if"
@@ -29,6 +47,58 @@ version = "1.0.4"
29
47
  source = "registry+https://github.com/rust-lang/crates.io-index"
30
48
  checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
31
49
 
50
+ [[package]]
51
+ name = "ciborium"
52
+ version = "0.2.2"
53
+ source = "registry+https://github.com/rust-lang/crates.io-index"
54
+ checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e"
55
+ dependencies = [
56
+ "ciborium-io",
57
+ "ciborium-ll",
58
+ "serde",
59
+ ]
60
+
61
+ [[package]]
62
+ name = "ciborium-io"
63
+ version = "0.2.2"
64
+ source = "registry+https://github.com/rust-lang/crates.io-index"
65
+ checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757"
66
+
67
+ [[package]]
68
+ name = "ciborium-ll"
69
+ version = "0.2.2"
70
+ source = "registry+https://github.com/rust-lang/crates.io-index"
71
+ checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9"
72
+ dependencies = [
73
+ "ciborium-io",
74
+ "half",
75
+ ]
76
+
77
+ [[package]]
78
+ name = "clap"
79
+ version = "4.6.6"
80
+ source = "registry+https://github.com/rust-lang/crates.io-index"
81
+ checksum = "473c7e07f409a8d772161724aa8db6a765a2532a70f9667eeb7b49d3d02fbdca"
82
+ dependencies = [
83
+ "clap_builder",
84
+ ]
85
+
86
+ [[package]]
87
+ name = "clap_builder"
88
+ version = "4.6.6"
89
+ source = "registry+https://github.com/rust-lang/crates.io-index"
90
+ checksum = "7b48fea5a88e9ae728a2dcbedbfc0e730f7d60da42e1cb049a83c9fb8b789889"
91
+ dependencies = [
92
+ "anstyle",
93
+ "clap_lex",
94
+ ]
95
+
96
+ [[package]]
97
+ name = "clap_lex"
98
+ version = "1.1.0"
99
+ source = "registry+https://github.com/rust-lang/crates.io-index"
100
+ checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9"
101
+
32
102
  [[package]]
33
103
  name = "convert_case"
34
104
  version = "0.6.0"
@@ -38,6 +108,46 @@ dependencies = [
38
108
  "unicode-segmentation",
39
109
  ]
40
110
 
111
+ [[package]]
112
+ name = "criterion"
113
+ version = "0.5.1"
114
+ source = "registry+https://github.com/rust-lang/crates.io-index"
115
+ checksum = "f2b12d017a929603d80db1831cd3a24082f8137ce19c69e6447f54f5fc8d692f"
116
+ dependencies = [
117
+ "anes",
118
+ "cast",
119
+ "ciborium",
120
+ "clap",
121
+ "criterion-plot",
122
+ "is-terminal",
123
+ "itertools",
124
+ "num-traits",
125
+ "once_cell",
126
+ "oorandom",
127
+ "regex",
128
+ "serde",
129
+ "serde_derive",
130
+ "serde_json",
131
+ "tinytemplate",
132
+ "walkdir",
133
+ ]
134
+
135
+ [[package]]
136
+ name = "criterion-plot"
137
+ version = "0.5.0"
138
+ source = "registry+https://github.com/rust-lang/crates.io-index"
139
+ checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1"
140
+ dependencies = [
141
+ "cast",
142
+ "itertools",
143
+ ]
144
+
145
+ [[package]]
146
+ name = "crunchy"
147
+ version = "0.2.4"
148
+ source = "registry+https://github.com/rust-lang/crates.io-index"
149
+ checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5"
150
+
41
151
  [[package]]
42
152
  name = "ctor"
43
153
  version = "0.2.9"
@@ -54,12 +164,35 @@ version = "0.1.13"
54
164
  source = "registry+https://github.com/rust-lang/crates.io-index"
55
165
  checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8"
56
166
 
167
+ [[package]]
168
+ name = "either"
169
+ version = "1.18.0"
170
+ source = "registry+https://github.com/rust-lang/crates.io-index"
171
+ checksum = "252afb9ae5eaa683babdc6a068b3f5726eb19e05070c731f9b2a23a7c3e8ed34"
172
+
173
+ [[package]]
174
+ name = "half"
175
+ version = "2.7.1"
176
+ source = "registry+https://github.com/rust-lang/crates.io-index"
177
+ checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b"
178
+ dependencies = [
179
+ "cfg-if",
180
+ "crunchy",
181
+ "zerocopy",
182
+ ]
183
+
57
184
  [[package]]
58
185
  name = "heck"
59
186
  version = "0.5.0"
60
187
  source = "registry+https://github.com/rust-lang/crates.io-index"
61
188
  checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
62
189
 
190
+ [[package]]
191
+ name = "hermit-abi"
192
+ version = "0.5.3"
193
+ source = "registry+https://github.com/rust-lang/crates.io-index"
194
+ checksum = "e17592d60ebacc7d5e169f4663c5f84f9161cc90328abcfe8456f41e4dfcb284"
195
+
63
196
  [[package]]
64
197
  name = "indoc"
65
198
  version = "2.0.7"
@@ -69,6 +202,32 @@ dependencies = [
69
202
  "rustversion",
70
203
  ]
71
204
 
205
+ [[package]]
206
+ name = "is-terminal"
207
+ version = "0.4.17"
208
+ source = "registry+https://github.com/rust-lang/crates.io-index"
209
+ checksum = "3640c1c38b8e4e43584d8df18be5fc6b0aa314ce6ebf51b53313d4306cca8e46"
210
+ dependencies = [
211
+ "hermit-abi",
212
+ "libc",
213
+ "windows-sys",
214
+ ]
215
+
216
+ [[package]]
217
+ name = "itertools"
218
+ version = "0.10.5"
219
+ source = "registry+https://github.com/rust-lang/crates.io-index"
220
+ checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
221
+ dependencies = [
222
+ "either",
223
+ ]
224
+
225
+ [[package]]
226
+ name = "itoa"
227
+ version = "1.0.18"
228
+ source = "registry+https://github.com/rust-lang/crates.io-index"
229
+ checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
230
+
72
231
  [[package]]
73
232
  name = "lexical-core"
74
233
  version = "1.0.6"
@@ -214,16 +373,32 @@ dependencies = [
214
373
  "libloading",
215
374
  ]
216
375
 
376
+ [[package]]
377
+ name = "num-traits"
378
+ version = "0.2.19"
379
+ source = "registry+https://github.com/rust-lang/crates.io-index"
380
+ checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
381
+ dependencies = [
382
+ "autocfg",
383
+ ]
384
+
217
385
  [[package]]
218
386
  name = "once_cell"
219
387
  version = "1.21.4"
220
388
  source = "registry+https://github.com/rust-lang/crates.io-index"
221
389
  checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
222
390
 
391
+ [[package]]
392
+ name = "oorandom"
393
+ version = "11.1.5"
394
+ source = "registry+https://github.com/rust-lang/crates.io-index"
395
+ checksum = "d6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41e"
396
+
223
397
  [[package]]
224
398
  name = "polyxml"
225
- version = "0.1.0"
399
+ version = "0.2.0"
226
400
  dependencies = [
401
+ "criterion",
227
402
  "lexical-core",
228
403
  "memchr",
229
404
  "pretty_assertions",
@@ -234,14 +409,14 @@ dependencies = [
234
409
 
235
410
  [[package]]
236
411
  name = "polyxml-c"
237
- version = "0.1.0"
412
+ version = "0.2.0"
238
413
  dependencies = [
239
414
  "polyxml",
240
415
  ]
241
416
 
242
417
  [[package]]
243
418
  name = "polyxml-js"
244
- version = "0.1.0"
419
+ version = "0.2.0"
245
420
  dependencies = [
246
421
  "napi",
247
422
  "napi-build",
@@ -251,7 +426,7 @@ dependencies = [
251
426
 
252
427
  [[package]]
253
428
  name = "polyxml-python"
254
- version = "0.1.0"
429
+ version = "0.2.0"
255
430
  dependencies = [
256
431
  "lexical-core",
257
432
  "polyxml",
@@ -402,6 +577,15 @@ version = "1.0.23"
402
577
  source = "registry+https://github.com/rust-lang/crates.io-index"
403
578
  checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f"
404
579
 
580
+ [[package]]
581
+ name = "same-file"
582
+ version = "1.0.6"
583
+ source = "registry+https://github.com/rust-lang/crates.io-index"
584
+ checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
585
+ dependencies = [
586
+ "winapi-util",
587
+ ]
588
+
405
589
  [[package]]
406
590
  name = "semver"
407
591
  version = "1.0.28"
@@ -415,6 +599,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
415
599
  checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba"
416
600
  dependencies = [
417
601
  "serde_core",
602
+ "serde_derive",
418
603
  ]
419
604
 
420
605
  [[package]]
@@ -437,6 +622,19 @@ dependencies = [
437
622
  "syn 3.0.5",
438
623
  ]
439
624
 
625
+ [[package]]
626
+ name = "serde_json"
627
+ version = "1.0.151"
628
+ source = "registry+https://github.com/rust-lang/crates.io-index"
629
+ checksum = "c841b55ecdae098c80dcae9cf767f6f8a0c2cdb3416bbef72181df4d0fe73f14"
630
+ dependencies = [
631
+ "itoa",
632
+ "memchr",
633
+ "serde",
634
+ "serde_core",
635
+ "zmij",
636
+ ]
637
+
440
638
  [[package]]
441
639
  name = "smallvec"
442
640
  version = "1.16.0"
@@ -491,6 +689,16 @@ dependencies = [
491
689
  "syn 3.0.5",
492
690
  ]
493
691
 
692
+ [[package]]
693
+ name = "tinytemplate"
694
+ version = "1.2.1"
695
+ source = "registry+https://github.com/rust-lang/crates.io-index"
696
+ checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc"
697
+ dependencies = [
698
+ "serde",
699
+ "serde_json",
700
+ ]
701
+
494
702
  [[package]]
495
703
  name = "unicode-ident"
496
704
  version = "1.0.24"
@@ -509,14 +717,68 @@ version = "0.2.4"
509
717
  source = "registry+https://github.com/rust-lang/crates.io-index"
510
718
  checksum = "7264e107f553ccae879d21fbea1d6724ac785e8c3bfc762137959b5802826ef3"
511
719
 
720
+ [[package]]
721
+ name = "walkdir"
722
+ version = "2.5.0"
723
+ source = "registry+https://github.com/rust-lang/crates.io-index"
724
+ checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
725
+ dependencies = [
726
+ "same-file",
727
+ "winapi-util",
728
+ ]
729
+
730
+ [[package]]
731
+ name = "winapi-util"
732
+ version = "0.1.11"
733
+ source = "registry+https://github.com/rust-lang/crates.io-index"
734
+ checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
735
+ dependencies = [
736
+ "windows-sys",
737
+ ]
738
+
512
739
  [[package]]
513
740
  name = "windows-link"
514
741
  version = "0.2.1"
515
742
  source = "registry+https://github.com/rust-lang/crates.io-index"
516
743
  checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
517
744
 
745
+ [[package]]
746
+ name = "windows-sys"
747
+ version = "0.61.2"
748
+ source = "registry+https://github.com/rust-lang/crates.io-index"
749
+ checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
750
+ dependencies = [
751
+ "windows-link",
752
+ ]
753
+
518
754
  [[package]]
519
755
  name = "yansi"
520
756
  version = "1.0.1"
521
757
  source = "registry+https://github.com/rust-lang/crates.io-index"
522
758
  checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049"
759
+
760
+ [[package]]
761
+ name = "zerocopy"
762
+ version = "0.8.57"
763
+ source = "registry+https://github.com/rust-lang/crates.io-index"
764
+ checksum = "d35102a9f36d089ccae9e4c6802bc118be4487b80aaffc0ab4e0cf5ce92d2873"
765
+ dependencies = [
766
+ "zerocopy-derive",
767
+ ]
768
+
769
+ [[package]]
770
+ name = "zerocopy-derive"
771
+ version = "0.8.57"
772
+ source = "registry+https://github.com/rust-lang/crates.io-index"
773
+ checksum = "146c01f5ab44258da43cf276c74a2763db2ff3969c9c652c3f2de07041d0b2bc"
774
+ dependencies = [
775
+ "proc-macro2",
776
+ "quote",
777
+ "syn 2.0.119",
778
+ ]
779
+
780
+ [[package]]
781
+ name = "zmij"
782
+ version = "1.0.23"
783
+ source = "registry+https://github.com/rust-lang/crates.io-index"
784
+ checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b"
@@ -3,7 +3,7 @@ resolver = "2"
3
3
  members = ["crates/polyxml-core", "crates/polyxml-python"]
4
4
 
5
5
  [workspace.package]
6
- version = "0.1.0"
6
+ version = "0.2.0"
7
7
  edition = "2021"
8
8
  rust-version = "1.80"
9
9
  license = "MIT"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: polyxml
3
- Version: 0.1.0
3
+ Version: 0.2.0
4
4
  Classifier: Development Status :: 4 - Beta
5
5
  Classifier: Intended Audience :: Developers
6
6
  Classifier: License :: OSI Approved :: MIT License
@@ -8,6 +8,7 @@ Classifier: Programming Language :: Rust
8
8
  Classifier: Programming Language :: Python :: 3
9
9
  Classifier: Programming Language :: Python :: 3.12
10
10
  Classifier: Programming Language :: Python :: 3.13
11
+ Classifier: Programming Language :: Python :: 3.14
11
12
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
12
13
  Classifier: Topic :: Text Processing :: Markup :: XML
13
14
  Classifier: Typing :: Typed
@@ -5,6 +5,7 @@ edition.workspace = true
5
5
  license.workspace = true
6
6
  authors.workspace = true
7
7
  repository.workspace = true
8
+ readme = "README.md"
8
9
  description = "Pure Rust high-performance streaming XML data-binding core engine"
9
10
  keywords = ["xml", "deserializer", "serializer", "data-binding", "quick-xml"]
10
11
  categories = ["parsing", "encoding"]
@@ -17,4 +18,9 @@ thiserror = "2.0"
17
18
  smallvec = "1.16"
18
19
 
19
20
  [dev-dependencies]
21
+ criterion = { version = "0.5", default-features = false, features = ["cargo_bench_support"] }
20
22
  pretty_assertions = "1.4"
23
+
24
+ [[bench]]
25
+ name = "core_benchmarks"
26
+ harness = false
@@ -0,0 +1,134 @@
1
+ # polyxml
2
+
3
+ [![Crates.io](https://img.shields.io/crates/v/polyxml.svg)](https://crates.io/crates/polyxml)
4
+ [![Docs.rs](https://docs.rs/polyxml/badge.svg)](https://docs.rs/polyxml)
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://github.com/nth-bailey/PolyXML/blob/main/LICENSE)
6
+
7
+ **PolyXML** is a high-performance, zero-copy streaming XML data-binding core engine built in Rust. It serves as the foundational native engine powering language bindings across Python, C/C++, Java, and Node.js.
8
+
9
+ ---
10
+
11
+ ## Features
12
+
13
+ - **High Throughput & Low Latency**: Built on top of [`quick-xml`](https://crates.io/crates/quick-xml) and [`lexical-core`](https://crates.io/crates/lexical-core) for fast, zero-copy byte slice parsing.
14
+ - **Dynamic Schema-Driven**: Decouples data model definitions from parsing logic using `ModelSchema` and `FieldSchema`.
15
+ - **Bidirectional**: Fast streaming deserialization and serialization with optional indentation formatting.
16
+ - **Security Hardened**: Built-in recursion depth limits protect against XML entity expansion and deeply nested denial-of-service (Billion Laughs) attacks.
17
+ - **Zero Heavy Allocations**: Uses `smallvec` and slice lookups to minimize intermediate heap allocations.
18
+
19
+ ---
20
+
21
+ ## Installation
22
+
23
+ Add `polyxml` to your `Cargo.toml`:
24
+
25
+ ```toml
26
+ [dependencies]
27
+ polyxml = "0.1.0"
28
+ ```
29
+
30
+ Or run:
31
+
32
+ ```bash
33
+ cargo add polyxml
34
+ ```
35
+
36
+ ---
37
+
38
+ ## Quickstart
39
+
40
+ ```rust
41
+ use std::sync::Arc;
42
+ use polyxml::{
43
+ deserialize, serialize,
44
+ FieldKind, FieldSchema, ModelSchema, PolyValue, ScalarType, ValueType,
45
+ };
46
+
47
+ fn main() -> Result<(), Box<dyn std::error::Error>> {
48
+ // 1. Define your model schema
49
+ let schema = ModelSchema::builder("User")
50
+ .field(FieldSchema::new(
51
+ "id",
52
+ b"id",
53
+ FieldKind::Attribute,
54
+ ValueType::Scalar(ScalarType::Int),
55
+ ))
56
+ .field(FieldSchema::new(
57
+ "name",
58
+ b"name",
59
+ FieldKind::Element,
60
+ ValueType::Scalar(ScalarType::String),
61
+ ))
62
+ .field(FieldSchema::new(
63
+ "score",
64
+ b"score",
65
+ FieldKind::Element,
66
+ ValueType::Scalar(ScalarType::Float),
67
+ ))
68
+ .build();
69
+
70
+ let xml = br#"<User id="42"><name>Alice</name><score>98.6</score></User>"#;
71
+
72
+ // 2. Deserialize XML bytes
73
+ let user = deserialize(xml, Arc::clone(&schema))?;
74
+ assert_eq!(user.get("id"), Some(&PolyValue::Int(42)));
75
+ assert_eq!(user.get("name"), Some(&PolyValue::String("Alice".into())));
76
+ assert_eq!(user.get("score"), Some(&PolyValue::Float(98.6)));
77
+
78
+ // 3. Serialize back to formatted XML
79
+ let output_xml = serialize("User", &user, &schema, Some(2))?;
80
+ println!("{}", std::str::from_utf8(&output_xml)?);
81
+
82
+ Ok(())
83
+ }
84
+ ```
85
+
86
+ ---
87
+
88
+ ## Nested Models & Lists
89
+
90
+ ```rust
91
+ use std::sync::Arc;
92
+ use polyxml::{FieldKind, FieldSchema, ModelSchema, ScalarType, ValueType};
93
+
94
+ // Sub-model
95
+ let item_schema = ModelSchema::builder("Item")
96
+ .field(FieldSchema::new("sku", b"sku", FieldKind::Attribute, ValueType::Scalar(ScalarType::String)))
97
+ .field(FieldSchema::new("qty", b"qty", FieldKind::Element, ValueType::Scalar(ScalarType::Int)))
98
+ .build();
99
+
100
+ // Parent model containing repeated sub-models
101
+ let order_schema = ModelSchema::builder("Order")
102
+ .field(FieldSchema::new("id", b"id", FieldKind::Attribute, ValueType::Scalar(ScalarType::String)))
103
+ .field(FieldSchema::new(
104
+ "items",
105
+ b"item",
106
+ FieldKind::Element,
107
+ ValueType::List(Box::new(ValueType::Nested(item_schema))),
108
+ ))
109
+ .build();
110
+ ```
111
+
112
+ ---
113
+
114
+ ## Security Limits
115
+
116
+ To defend against deeply nested payloads or XML entity expansion denial-of-service, specify a recursion depth limit:
117
+
118
+ ```rust
119
+ let val = polyxml::deserialize_with_limit(xml_bytes, schema, 64)?;
120
+ ```
121
+
122
+ ---
123
+
124
+ ## Documentation & Repository
125
+
126
+ - **Full Documentation**: [https://nth-bailey.github.io/PolyXML/](https://nth-bailey.github.io/PolyXML/)
127
+ - **API Reference**: [https://docs.rs/polyxml](https://docs.rs/polyxml)
128
+ - **Source Code**: [https://github.com/nth-bailey/PolyXML](https://github.com/nth-bailey/PolyXML)
129
+
130
+ ---
131
+
132
+ ## License
133
+
134
+ Licensed under the [MIT License](https://github.com/nth-bailey/PolyXML/blob/main/LICENSE).