diff --git a/src/core/xfa/bind.js b/src/core/xfa/bind.js index 3864f6bd5..3cf7bed0d 100644 --- a/src/core/xfa/bind.js +++ b/src/core/xfa/bind.js @@ -45,6 +45,8 @@ import { createDataNode, searchNode } from "./som.js"; import { NamespaceIds } from "./namespaces.js"; import { warn } from "../../shared/util.js"; +const NS_DATASETS = NamespaceIds.datasets.id; + function createText(content) { const node = new Text({}); node[$content] = content; @@ -501,8 +503,12 @@ class Binder { if (dataChildren.length > 0) { this._bindOccurrences(child, [dataChildren[0]], null); } else if (this.emptyMerge) { + const nsId = + dataNode[$namespaceId] === NS_DATASETS + ? -1 + : dataNode[$namespaceId]; const dataChild = (child[$data] = new XmlObject( - dataNode[$namespaceId], + nsId, child.name || "root" )); dataNode[$appendChild](dataChild); @@ -625,10 +631,11 @@ class Binder { if (!match) { // We're in matchTemplate mode so create a node in data to reflect // what we've in template. - match = child[$data] = new XmlObject( - dataNode[$namespaceId], - child.name - ); + const nsId = + dataNode[$namespaceId] === NS_DATASETS + ? -1 + : dataNode[$namespaceId]; + match = child[$data] = new XmlObject(nsId, child.name); if (this.emptyMerge) { match[$consumed] = true; } diff --git a/src/core/xfa/som.js b/src/core/xfa/som.js index 515b69671..6955292b1 100644 --- a/src/core/xfa/som.js +++ b/src/core/xfa/som.js @@ -23,6 +23,7 @@ import { XFAObjectArray, XmlObject, } from "./xfa_object.js"; +import { NamespaceIds } from "./namespaces.js"; import { warn } from "../../shared/util.js"; const namePattern = /^[^.[]+/; @@ -51,6 +52,7 @@ const shortcuts = new Map([ ]); const somCache = new WeakMap(); +const NS_DATASETS = NamespaceIds.datasets.id; function parseIndex(index) { index = index.trim(); @@ -261,7 +263,8 @@ function createNodes(root, path) { let node = null; for (const { name, index } of path) { for (let i = 0, ii = !isFinite(index) ? 0 : index; i <= ii; i++) { - node = new XmlObject(root[$namespaceId], name); + const nsId = root[$namespaceId] === NS_DATASETS ? -1 : root[$namespaceId]; + node = new XmlObject(nsId, name); root[$appendChild](node); } diff --git a/src/core/xfa/xfa_object.js b/src/core/xfa/xfa_object.js index e6bf5ed16..785950e8c 100644 --- a/src/core/xfa/xfa_object.js +++ b/src/core/xfa/xfa_object.js @@ -976,8 +976,11 @@ class XmlObject extends XFAObject { this[$content] = value.toString(); } - [$dump]() { + [$dump](hasNS = false) { const dumped = Object.create(null); + if (hasNS) { + dumped.$ns = this[$namespaceId]; + } if (this[$content]) { dumped.$content = this[$content]; } @@ -985,7 +988,7 @@ class XmlObject extends XFAObject { dumped.children = []; for (const child of this[_children]) { - dumped.children.push(child[$dump]()); + dumped.children.push(child[$dump](hasNS)); } dumped.attributes = Object.create(null); diff --git a/test/unit/xfa_parser_spec.js b/test/unit/xfa_parser_spec.js index 8ef286822..37edaba2b 100644 --- a/test/unit/xfa_parser_spec.js +++ b/test/unit/xfa_parser_spec.js @@ -841,6 +841,67 @@ describe("XFAParser", function () { expect(searchNode(data, data, "A")[0][$dump]()).toEqual(expected); }); + it("should make a basic binding and create a non-existing node with namespaceId equal to -1", function () { + const xml = ` + + + + + `; + const root = new XFAParser().parse(xml); + const binder = new Binder(root); + const form = binder.bind(); + const data = binder.getData(); + + expect( + searchNode(form, form, "A.B.D.value.text")[0][$dump]().$content + ).toBe("foobar"); + + // Created nodes mustn't belong to xfa:datasets namespace. + const expected = { + $name: "A", + $ns: -1, + attributes: {}, + children: [ + { + $name: "B", + $ns: -1, + attributes: {}, + children: [ + { + $name: "C", + $ns: -1, + attributes: {}, + children: [], + }, + { + $name: "D", + $ns: -1, + attributes: {}, + children: [], + }, + ], + }, + ], + }; + + expect(searchNode(data, data, "A")[0][$dump](/* hasNS */ true)).toEqual( + expected + ); + }); + it("should make another basic binding", function () { const xml = `