1
0
Fork 0
mirror of https://github.com/mozilla/pdf.js.git synced 2025-04-21 23:58:07 +02:00

XFA -- Add support for SOM expressions (#12983)

- specifications: http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.364.2157&rep=rep1&type=pdf#page=87;
 - add a parser for SOM expressions;
 - add search functions to resolve those expressions;
 - search functions will be used to bind data into template.
This commit is contained in:
calixteman 2021-02-24 01:13:02 -08:00 committed by GitHub
parent fafe039849
commit 45329af926
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 610 additions and 3 deletions

View file

@ -13,7 +13,14 @@
* limitations under the License.
*/
import { $dump, $getChildren, $text } from "../../src/core/xfa/xfa_object.js";
import {
$dump,
$getChildren,
$getChildrenByClass,
$getChildrenByName,
$text,
} from "../../src/core/xfa/xfa_object.js";
import { searchNode } from "../../src/core/xfa/som.js";
import { XFAParser } from "../../src/core/xfa/parser.js";
describe("XFAParser", function () {
@ -416,4 +423,240 @@ describe("XFAParser", function () {
expect(field.value.text.$content).toEqual("Overriding text");
});
});
describe("Search in XFA", function () {
it("should search some nodes in a template object", function () {
const xml = `
<?xml version="1.0"?>
<xdp:xdp xmlns:xdp="http://ns.adobe.com/xdp/">
<template xmlns="http://www.xfa.org/schema/xfa-template/3.3">
<subform name="Receipt" id="l">
<subform id="m">
<field name="Description" id="a"> </field>
<field name="Units" id="b"> </field>
<field name="Unit_Price" id="c"> </field>
<field name="Total_Price" id="d"> </field>
</subform>
<subform id="n">
<field name="Description" id="e"> </field>
<field name="Units" id="f"> </field>
<field name="Unit_Price" id="g"> </field>
<field name="Total_Price" id="h"> </field>
</subform>
<subform name="foo" id="o">
<field name="Description" id="p"> </field>
<field name="Units" id="q"> </field>
<field name="Unit_Price" id="r"> </field>
<field name="Total_Price" id="s"> </field>
</subform>
<field name="Sub_Total" id="i"> </field>
<field name="Tax" id="j"> </field>
<field name="Total_Price" id="k"> </field>
</subform>
</template>
</xdp:xdp>
`;
const root = new XFAParser().parse(xml);
let found = root[$getChildrenByName]("subform", true);
expect(found.map(x => x.id)).toEqual(["l", "m", "n", "o"]);
found = root[$getChildrenByName]("Total_Price", true);
expect(found.map(x => x.id)).toEqual(["d", "h", "s", "k"]);
found = root.template[$getChildrenByName]("Receipt", false);
const receipt = found[0];
found = receipt[$getChildrenByName]("Total_Price", false);
expect(found.map(x => x.id)).toEqual(["d", "h", "k"]);
expect(receipt[$getChildrenByClass]("name")).toEqual("Receipt");
const subforms = receipt[$getChildrenByClass]("subform");
expect(subforms.children.map(x => x.id)).toEqual(["m", "n", "o"]);
});
it("should search some nodes in a template object using SOM", function () {
const xml = `
<?xml version="1.0"?>
<xdp:xdp xmlns:xdp="http://ns.adobe.com/xdp/">
<template xmlns="http://www.xfa.org/schema/xfa-template/3.3">
<subform name="Receipt" id="l">
<subform id="m">
<field name="Description" id="a"> </field>
<field name="Units" id="b"> </field>
<field name="Unit_Price" id="c"> </field>
<field name="Total_Price" id="d"> </field>
</subform>
<subform id="n">
<field name="Description" id="e"> </field>
<field name="Units" id="f"> </field>
<field name="Unit_Price" id="g"> </field>
<field name="Total_Price" id="h"> </field>
</subform>
<subform name="foo" id="o">
<field name="Description" id="p"> </field>
<field name="Units" id="q"> </field>
<field name="Unit_Price" id="r"> </field>
<field name="Total_Price" id="s"> </field>
</subform>
<field name="Sub_Total" id="i"> </field>
<field name="Tax" id="j"> </field>
<field name="Total_Price" id="k"> </field>
</subform>
</template>
</xdp:xdp>
`;
const root = new XFAParser().parse(xml);
expect(searchNode(root, null, "$template..Description.id")[$text]()).toBe(
"a"
);
expect(searchNode(root, null, "$template..Description.id")[$text]()).toBe(
"a"
);
expect(
searchNode(root, null, "$template..Description[0].id")[$text]()
).toBe("a");
expect(
searchNode(root, null, "$template..Description[1].id")[$text]()
).toBe("e");
expect(
searchNode(root, null, "$template..Description[2].id")[$text]()
).toBe("p");
expect(searchNode(root, null, "$template.Receipt.id")[$text]()).toBe("l");
expect(
searchNode(root, null, "$template.Receipt.Description[1].id")[$text]()
).toBe("e");
expect(searchNode(root, null, "$template.Receipt.Description[2]")).toBe(
null
);
expect(
searchNode(root, null, "$template.Receipt.foo.Description.id")[$text]()
).toBe("p");
expect(
searchNode(root, null, "$template.#subform.Sub_Total.id")[$text]()
).toBe("i");
expect(
searchNode(root, null, "$template.#subform.Units.id")[$text]()
).toBe("b");
expect(
searchNode(root, null, "$template.#subform.Units.parent.id")[$text]()
).toBe("m");
});
it("should search some nodes in a datasets object", function () {
const xml = `
<?xml version="1.0"?>
<xdp:xdp xmlns:xdp="http://ns.adobe.com/xdp/">
<xfa:datasets xmlns:xfa="http://www.xfa.org/schema/xfa-data/1.0/">
<xfa:data>
<Receipt>
<Page>1</Page>
<Detail PartNo="GS001">
<Description>Giant Slingshot</Description>
<Units>1</Units>
<Unit_Price>250.00</Unit_Price>
<Total_Price>250.00</Total_Price>
</Detail>
<Page>2</Page>
<Detail PartNo="RRB-LB">
<Description>Road Runner Bait, large bag</Description>
<Units>5</Units>
<Unit_Price>12.00</Unit_Price>
<Total_Price>60.00</Total_Price>
</Detail>
<Sub_Total>310.00</Sub_Total>
<Tax>24.80</Tax>
<Total_Price>334.80</Total_Price>
</Receipt>
</xfa:data>
</xfa:datasets>
</xdp:xdp>
`;
const root = new XFAParser().parse(xml);
const data = root.datasets.data;
let found = data[$getChildrenByName]("Description", true);
expect(found.map(x => x[$text]())).toEqual([
"Giant Slingshot",
"Road Runner Bait, large bag",
]);
found = data[$getChildrenByName]("Total_Price", true);
expect(found.map(x => x[$text]())).toEqual(["250.00", "60.00", "334.80"]);
});
it("should search some nodes using SOM from a non-root node", function () {
const xml = `
<?xml version="1.0"?>
<xdp:xdp xmlns:xdp="http://ns.adobe.com/xdp/">
<xfa:datasets xmlns:xfa="http://www.xfa.org/schema/xfa-data/1.0/">
<xfa:data>
<Receipt>
<Page>1</Page>
<Detail PartNo="GS001">
<Description>Giant Slingshot</Description>
<Units>1</Units>
<Unit_Price>250.00</Unit_Price>
<Total_Price>250.00</Total_Price>
</Detail>
<Page>2</Page>
<Detail PartNo="RRB-LB">
<Description>Road Runner Bait, large bag</Description>
<Units>5</Units>
<Unit_Price>12.00</Unit_Price>
<Total_Price>60.00</Total_Price>
</Detail>
<Sub_Total>310.00</Sub_Total>
<Tax>24.80</Tax>
<Total_Price>334.80</Total_Price>
</Receipt>
</xfa:data>
</xfa:datasets>
</xdp:xdp>
`;
const root = new XFAParser().parse(xml);
const [receipt] = root.datasets.data[$getChildren]("Receipt");
expect(
searchNode(root, receipt, "Detail[*].Total_Price").map(x => x[$text]())
).toEqual(["250.00", "60.00"]);
const units = searchNode(root, receipt, "Detail[1].Units");
expect(units[$text]()).toBe("5");
let found = searchNode(root, units, "Total_Price");
expect(found[$text]()).toBe("60.00");
found = searchNode(root, units, "Total_Pric");
expect(found).toEqual(null);
});
it("should search some nodes in a datasets object using SOM", function () {
const xml = `
<?xml version="1.0"?>
<xdp:xdp xmlns:xdp="http://ns.adobe.com/xdp/">
<xfa:datasets xmlns:xfa="http://www.xfa.org/schema/xfa-data/1.0/">
<xfa:data>
<Receipt Detail="Acme">
<Detail>foo</Detail>
<Detail>bar</Detail>
</Receipt>
</xfa:data>
</xfa:datasets>
</xdp:xdp>
`;
const root = new XFAParser().parse(xml);
expect(searchNode(root, null, "$data.Receipt.Detail")[$text]()).toBe(
"Acme"
);
expect(searchNode(root, null, "$data.Receipt.Detail[0]")[$text]()).toBe(
"Acme"
);
expect(searchNode(root, null, "$data.Receipt.Detail[1]")[$text]()).toBe(
"foo"
);
expect(searchNode(root, null, "$data.Receipt.Detail[2]")[$text]()).toBe(
"bar"
);
});
});
});