1use crate::types::{FieldValue, FormData};
13use indexmap::IndexMap;
14use xfa_layout_engine::form::{DrawContent, FormNodeId, FormNodeType, FormTree};
15
16pub fn json_to_form_tree(data: &FormData, tree: &mut FormTree, root: FormNodeId) {
21 let node = tree.get(root);
22 let children: Vec<FormNodeId> = node.children.clone();
23
24 match &node.node_type {
25 FormNodeType::Root | FormNodeType::PageSet | FormNodeType::PageArea { .. } => {
26 for child_id in children {
27 merge_node(data, tree, child_id, "");
28 }
29 }
30 _ => {
31 merge_node(data, tree, root, "");
32 }
33 }
34}
35
36fn merge_node(data: &FormData, tree: &mut FormTree, node_id: FormNodeId, parent_path: &str) {
38 let node = tree.get(node_id);
39 let name = node.name.clone();
40 let path = if parent_path.is_empty() {
41 name.clone()
42 } else {
43 format!("{parent_path}.{name}")
44 };
45
46 let node_type = node.node_type.clone();
47 let children: Vec<FormNodeId> = node.children.clone();
48 let is_repeating = node.occur.is_repeating();
49
50 match node_type {
51 FormNodeType::Field { .. } => {
52 if let Some(value) = data.fields.get(&path) {
53 let string_value = field_value_to_string(value);
54 tree.get_mut(node_id).node_type = FormNodeType::Field {
55 value: string_value,
56 };
57 }
58 }
59 FormNodeType::Draw(..) => {
60 if let Some(value) = data.fields.get(&path) {
61 let string_value = field_value_to_string(value);
62 tree.get_mut(node_id).node_type =
63 FormNodeType::Draw(DrawContent::Text(string_value));
64 }
65 }
66 FormNodeType::Image { .. } => {
67 }
69 FormNodeType::Subform | FormNodeType::Area | FormNodeType::ExclGroup => {
72 if is_repeating {
73 } else {
76 merge_children_with_repeating_groups(data, tree, &children, &path);
77 }
78 }
79 FormNodeType::SubformSet
80 | FormNodeType::Root
81 | FormNodeType::PageSet
82 | FormNodeType::PageArea { .. } => {
83 merge_children_with_repeating_groups(data, tree, &children, &path);
84 }
85 }
86}
87
88fn merge_children_with_repeating_groups(
91 data: &FormData,
92 tree: &mut FormTree,
93 children: &[FormNodeId],
94 parent_path: &str,
95) {
96 let mut repeating_counts: IndexMap<String, usize> = IndexMap::new();
98
99 for &child_id in children {
100 let child = tree.get(child_id);
101 let is_repeating = child.occur.is_repeating();
102
103 if is_repeating {
104 let name = child.name.clone();
105 let index = repeating_counts.get(&name).copied().unwrap_or(0);
106 repeating_counts.insert(name.clone(), index + 1);
107
108 let path = if parent_path.is_empty() {
109 name
110 } else {
111 format!("{parent_path}.{name}")
112 };
113
114 if let Some(FieldValue::Array(instances)) = data.fields.get(&path) {
116 if let Some(instance_data) = instances.get(index) {
117 merge_instance(tree, child_id, instance_data);
118 }
119 }
120 } else {
121 merge_node(data, tree, child_id, parent_path);
122 }
123 }
124}
125
126fn merge_instance(
129 tree: &mut FormTree,
130 node_id: FormNodeId,
131 instance_data: &IndexMap<String, FieldValue>,
132) {
133 let children: Vec<FormNodeId> = tree.get(node_id).children.clone();
134
135 for &child_id in &children {
136 let child = tree.get(child_id);
137 let child_name = child.name.clone();
138 let child_type = child.node_type.clone();
139
140 match child_type {
141 FormNodeType::Field { .. } => {
142 if let Some(value) = instance_data.get(&child_name) {
143 let string_value = field_value_to_string(value);
144 tree.get_mut(child_id).node_type = FormNodeType::Field {
145 value: string_value,
146 };
147 }
148 }
149 FormNodeType::Draw(..) => {
150 if let Some(value) = instance_data.get(&child_name) {
151 let string_value = field_value_to_string(value);
152 tree.get_mut(child_id).node_type =
153 FormNodeType::Draw(DrawContent::Text(string_value));
154 }
155 }
156 FormNodeType::Subform => {
157 let nested_prefix = format!("{child_name}.");
159 let nested_data: IndexMap<String, FieldValue> = instance_data
160 .iter()
161 .filter_map(|(k, v)| {
162 k.strip_prefix(&nested_prefix)
163 .map(|rest| (rest.to_string(), v.clone()))
164 })
165 .collect();
166 if !nested_data.is_empty() {
167 merge_instance(tree, child_id, &nested_data);
168 }
169 }
170 _ => {}
171 }
172 }
173}
174
175fn field_value_to_string(value: &FieldValue) -> String {
177 match value {
178 FieldValue::Text(s) => s.clone(),
179 FieldValue::Number(n) => {
180 if *n == n.trunc() && n.abs() < 1e15 {
181 format!("{}", *n as i64)
182 } else {
183 n.to_string()
184 }
185 }
186 FieldValue::Boolean(b) => if *b { "1" } else { "0" }.to_string(),
187 FieldValue::Null => String::new(),
188 FieldValue::Array(_) => String::new(),
189 }
190}
191
192#[cfg(test)]
193mod tests {
194 use super::*;
195 use crate::export::form_tree_to_json;
196 use indexmap::IndexMap;
197 use xfa_layout_engine::form::{FormNode, Occur};
198 use xfa_layout_engine::text::FontMetrics;
199 use xfa_layout_engine::types::{BoxModel, LayoutStrategy};
200
201 fn make_field(tree: &mut FormTree, name: &str, value: &str) -> FormNodeId {
202 tree.add_node(FormNode {
203 name: name.to_string(),
204 node_type: FormNodeType::Field {
205 value: value.to_string(),
206 },
207 box_model: BoxModel::default(),
208 layout: LayoutStrategy::Positioned,
209 children: vec![],
210 occur: Occur::once(),
211 font: FontMetrics::default(),
212 calculate: None,
213 validate: None,
214 column_widths: vec![],
215 col_span: 1,
216 })
217 }
218
219 fn make_subform(tree: &mut FormTree, name: &str, children: Vec<FormNodeId>) -> FormNodeId {
220 make_subform_with_occur(tree, name, children, Occur::once())
221 }
222
223 fn make_subform_with_occur(
224 tree: &mut FormTree,
225 name: &str,
226 children: Vec<FormNodeId>,
227 occur: Occur,
228 ) -> FormNodeId {
229 tree.add_node(FormNode {
230 name: name.to_string(),
231 node_type: FormNodeType::Subform,
232 box_model: BoxModel::default(),
233 layout: LayoutStrategy::TopToBottom,
234 children,
235 occur,
236 font: FontMetrics::default(),
237 calculate: None,
238 validate: None,
239 column_widths: vec![],
240 col_span: 1,
241 })
242 }
243
244 fn make_root(tree: &mut FormTree, children: Vec<FormNodeId>) -> FormNodeId {
245 tree.add_node(FormNode {
246 name: "Root".to_string(),
247 node_type: FormNodeType::Root,
248 box_model: BoxModel::default(),
249 layout: LayoutStrategy::TopToBottom,
250 children,
251 occur: Occur::once(),
252 font: FontMetrics::default(),
253 calculate: None,
254 validate: None,
255 column_widths: vec![],
256 col_span: 1,
257 })
258 }
259
260 #[test]
261 fn roundtrip_simple_form() {
262 let mut tree = FormTree::new();
263 let name = make_field(&mut tree, "Name", "Original");
264 let amount = make_field(&mut tree, "Amount", "100");
265 let form = make_subform(&mut tree, "form1", vec![name, amount]);
266 let root = make_root(&mut tree, vec![form]);
267
268 let mut data = form_tree_to_json(&tree, root);
270 data.fields.insert(
271 "form1.Name".to_string(),
272 FieldValue::Text("Updated".to_string()),
273 );
274 data.fields
275 .insert("form1.Amount".to_string(), FieldValue::Number(200.0));
276
277 json_to_form_tree(&data, &mut tree, root);
278
279 let exported = form_tree_to_json(&tree, root);
281 assert_eq!(
282 exported.fields.get("form1.Name"),
283 Some(&FieldValue::Text("Updated".to_string()))
284 );
285 assert_eq!(
286 exported.fields.get("form1.Amount"),
287 Some(&FieldValue::Number(200.0))
288 );
289 }
290
291 #[test]
292 fn import_boolean_as_zero_one() {
293 let mut tree = FormTree::new();
294 let check = make_field(&mut tree, "Active", "0");
295 let form = make_subform(&mut tree, "form1", vec![check]);
296 let root = make_root(&mut tree, vec![form]);
297
298 let mut fields = IndexMap::new();
299 fields.insert("form1.Active".to_string(), FieldValue::Boolean(true));
300 let data = FormData { fields };
301
302 json_to_form_tree(&data, &mut tree, root);
303
304 match &tree.get(check).node_type {
306 FormNodeType::Field { value } => assert_eq!(value, "1"),
307 _ => panic!("Expected Field"),
308 }
309 }
310
311 #[test]
312 fn import_null_clears_field() {
313 let mut tree = FormTree::new();
314 let field = make_field(&mut tree, "Note", "something");
315 let form = make_subform(&mut tree, "form1", vec![field]);
316 let root = make_root(&mut tree, vec![form]);
317
318 let mut fields = IndexMap::new();
319 fields.insert("form1.Note".to_string(), FieldValue::Null);
320 let data = FormData { fields };
321
322 json_to_form_tree(&data, &mut tree, root);
323
324 match &tree.get(field).node_type {
325 FormNodeType::Field { value } => assert_eq!(value, ""),
326 _ => panic!("Expected Field"),
327 }
328 }
329
330 #[test]
331 #[allow(clippy::approx_constant)]
334 fn field_value_to_string_formats() {
335 assert_eq!(field_value_to_string(&FieldValue::Number(42.0)), "42");
336 assert_eq!(field_value_to_string(&FieldValue::Number(3.14)), "3.14");
337 assert_eq!(field_value_to_string(&FieldValue::Boolean(true)), "1");
338 assert_eq!(field_value_to_string(&FieldValue::Boolean(false)), "0");
339 assert_eq!(field_value_to_string(&FieldValue::Null), "");
340 assert_eq!(
341 field_value_to_string(&FieldValue::Text("hi".to_string())),
342 "hi"
343 );
344 }
345
346 #[test]
347 fn import_repeating_by_index_not_always_first() {
348 let mut tree = FormTree::new();
350 let desc1 = make_field(&mut tree, "Desc", "old1");
351 let qty1 = make_field(&mut tree, "Qty", "0");
352 let item1 = make_subform_with_occur(
353 &mut tree,
354 "Item",
355 vec![desc1, qty1],
356 Occur::repeating(0, None, 2),
357 );
358
359 let desc2 = make_field(&mut tree, "Desc", "old2");
360 let qty2 = make_field(&mut tree, "Qty", "0");
361 let item2 = make_subform_with_occur(
362 &mut tree,
363 "Item",
364 vec![desc2, qty2],
365 Occur::repeating(0, None, 2),
366 );
367
368 let form = make_subform(&mut tree, "form1", vec![item1, item2]);
369 let root = make_root(&mut tree, vec![form]);
370
371 let mut instance0 = IndexMap::new();
373 instance0.insert("Desc".to_string(), FieldValue::Text("Widget A".to_string()));
374 instance0.insert("Qty".to_string(), FieldValue::Number(10.0));
375 let mut instance1 = IndexMap::new();
376 instance1.insert("Desc".to_string(), FieldValue::Text("Widget B".to_string()));
377 instance1.insert("Qty".to_string(), FieldValue::Number(5.0));
378
379 let mut fields = IndexMap::new();
380 fields.insert(
381 "form1.Item".to_string(),
382 FieldValue::Array(vec![instance0, instance1]),
383 );
384 let data = FormData { fields };
385
386 json_to_form_tree(&data, &mut tree, root);
387
388 match &tree.get(desc1).node_type {
390 FormNodeType::Field { value } => assert_eq!(value, "Widget A"),
391 _ => panic!("Expected Field"),
392 }
393 match &tree.get(desc2).node_type {
394 FormNodeType::Field { value } => assert_eq!(value, "Widget B"),
395 _ => panic!("Expected Field"),
396 }
397 match &tree.get(qty1).node_type {
398 FormNodeType::Field { value } => assert_eq!(value, "10"),
399 _ => panic!("Expected Field"),
400 }
401 match &tree.get(qty2).node_type {
402 FormNodeType::Field { value } => assert_eq!(value, "5"),
403 _ => panic!("Expected Field"),
404 }
405 }
406
407 #[test]
408 fn import_nested_subform_inside_repeating() {
409 let mut tree = FormTree::new();
411
412 let street1 = make_field(&mut tree, "Street", "old");
414 let addr1 = make_subform(&mut tree, "Address", vec![street1]);
415 let name1 = make_field(&mut tree, "Name", "old");
416 let item1 = make_subform_with_occur(
417 &mut tree,
418 "Item",
419 vec![name1, addr1],
420 Occur::repeating(0, None, 2),
421 );
422
423 let street2 = make_field(&mut tree, "Street", "old");
424 let addr2 = make_subform(&mut tree, "Address", vec![street2]);
425 let name2 = make_field(&mut tree, "Name", "old");
426 let item2 = make_subform_with_occur(
427 &mut tree,
428 "Item",
429 vec![name2, addr2],
430 Occur::repeating(0, None, 2),
431 );
432
433 let form = make_subform(&mut tree, "form1", vec![item1, item2]);
434 let root = make_root(&mut tree, vec![form]);
435
436 let mut inst0 = IndexMap::new();
438 inst0.insert("Name".to_string(), FieldValue::Text("Alice".to_string()));
439 inst0.insert(
440 "Address.Street".to_string(),
441 FieldValue::Text("123 Main St".to_string()),
442 );
443 let mut inst1 = IndexMap::new();
444 inst1.insert("Name".to_string(), FieldValue::Text("Bob".to_string()));
445 inst1.insert(
446 "Address.Street".to_string(),
447 FieldValue::Text("456 Oak Ave".to_string()),
448 );
449
450 let mut fields = IndexMap::new();
451 fields.insert(
452 "form1.Item".to_string(),
453 FieldValue::Array(vec![inst0, inst1]),
454 );
455 let data = FormData { fields };
456
457 json_to_form_tree(&data, &mut tree, root);
458
459 match &tree.get(name1).node_type {
461 FormNodeType::Field { value } => assert_eq!(value, "Alice"),
462 _ => panic!("Expected Field"),
463 }
464 match &tree.get(street1).node_type {
465 FormNodeType::Field { value } => assert_eq!(value, "123 Main St"),
466 _ => panic!("Expected Field"),
467 }
468 match &tree.get(name2).node_type {
469 FormNodeType::Field { value } => assert_eq!(value, "Bob"),
470 _ => panic!("Expected Field"),
471 }
472 match &tree.get(street2).node_type {
473 FormNodeType::Field { value } => assert_eq!(value, "456 Oak Ave"),
474 _ => panic!("Expected Field"),
475 }
476 }
477}