我一直在使用iText
库作为Java
来自动填充PDF文档。我要做的第一件事是映射每个字段。一旦我映射了每个字段,就将变量名称保存到Strings
中,以便于访问。
到现在为止还挺好。问题是我有6个具有相同变量名的复选框。例如,它们被命名为topmostSubform[0].Page2[0].p2_cb01[0]
。
通过一些测试,我可以弄清楚,如果我选中第一个复选框,则topmostSubform[0].Page2[0].p2_cb01[0] = 1
如果我检查第二个(自动取消选中第一个),则topmostSubform[0].Page2[0].p2_cb01[0] = 2
然后依次topmostSubform[0].Page2[0].p2_cb01[0] = 3
,直到获得最后一个数字6
。
我正在使用form.setField("topmostSubform[0].Page2[0].p2_cb01[0]", "1");
填写字段。当我填写值1
时,第一个复选框被选中,但是当我填写应签名的2
数字时,第二个复选框不起作用。如果我选择2, 3, 4, 5 or 6
没关系,那就行不通了,复选框为空,我无法对其进行检查。
这是一段代码:
String _5_1 = "topmostSubform[0].Page2[0].p2_cb01[0]";
AcroFields form = stamper.getAcroFields();
form.setField(_5_1, "3");
拜托,我需要建议。
最佳答案
请允许我引用ISO-32000-1第12.7.3.2节“字段名称”:
如果我们将其应用于您的问题:不同的字段字典可能具有相同的名称topmostSubform[0].Page2[0].p2_cb01[0]
。此类字段字典是的不同表示形式,同一字段则应具有相同的值。
有两种选择:
topmostSubform[0].Page2[0].p2_cb01[0]
)具有不同的值,则您没有有效的PDF文件:它违反了ISO-32000-1,这是官方的PDF规范。 如果应用选项1,请放弃所有希望:您的PDF不好。修复或扔掉。如果应用选项2,请共享PDF。
检查PDF文件后更新:
选项2适用。您有一个混合表单,这意味着该表单在PDF中有两次描述,一次是使用AcroForm技术,一次是使用XFA。请先阅读我对以下问题的回答:PDFTK and removing the XFA format
在Adobe Reader中打开PDF时,您会注意到这些字段就像是单选按钮一样。当您单击一个时,它被选中,但是当您单击另一个时,它被选择了,但是第一个不再被选择。
您将看到XFA中描述的表单,并且XFA表单和AcroForm描述之间有一些重要的区别。这不是错误。它是混合形式固有的。
当您使用以下表格填写表格时:
form.setField("topmostSubform[0].Page2[0].p2_cb01[0]", "1");
iText可以正确地填写AcroForm,但是它不能填写XFA表单,因为iText对应该在XFA流中设置相应值的位置(实际上是用XML表示)进行了有根据的猜测(不是准确的猜测)。有关更多详细信息,请参见iText in Action - Second Edition的第8章。
在这种情况下,我通常要做的就是问他是否可以安全丢弃XFA部分的人所做的事情:我删除了XFA部分:
AcroFields form = stamper.getAcroFields();
form.removeXfa();
这极大地简化了事情,但是还不能解决您的问题。为了解决您的问题,我们需要查看PDF内部:
如屏幕截图所示(取自iText RUPS),该表单有两种不同的描述:您有一个
/Fields
数组(AcroForm描述),并且您有一个/XFA
部分,该部分由不同的流组成,如果您加入它们,形成一个大型XML文件。我们还看到您认为只有一个字段
topmostSubform[0].Page2[0].p2_cb01[0]
,实际上有6个字段:topmostSubform[0].Page2[0].p2_cb01[0]
topmostSubform[0].Page2[0].p2_cb01[1]
topmostSubform[0].Page2[0].p2_cb01[2]
topmostSubform[0].Page2[0].p2_cb01[3]
topmostSubform[0].Page2[0].p2_cb01[4]
topmostSubform[0].Page2[0].p2_cb01[5]
现在,让我们看一下这些字段。
这是
topmostSubform[0].Page2[0].p2_cb01[0]
字段:这是
topmostSubform[0].Page2[0].p2_cb01[0]
字段:这些是AcroForm复选框,但是有一条对人类有意义的说明:仅选择一个。该说明只能由人类理解,而不能由机器或软件理解。
我第一次编写FillHybridForm示例的尝试失败了,因为我犯了一个与您类似的错误。我对不同的外观状态看得不够仔细。我以为
topmostSubform[0].Page2[0].p2_cb01[0]
的值上的是0
,topmostSubform[0].Page2[0].p2_cb01[1]
的是1
,依此类推。不是... 的topmostSubform[0].Page2[0].p2_cb01[0]
的值为1
,topmostSubform[0].Page2[0].p2_cb01[1]
的值为2
,依此类推。这是您可以填写所有复选框的方式:
public void manipulatePdf(String src, String dest) throws DocumentException, IOException {
PdfReader reader = new PdfReader(src);
PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(dest));
AcroFields form = stamper.getAcroFields();
form.removeXfa();
form.setField("topmostSubform[0].Page2[0].p2_cb01[0]", "1");
form.setField("topmostSubform[0].Page2[0].p2_cb01[1]", "2");
form.setField("topmostSubform[0].Page2[0].p2_cb01[2]", "3");
form.setField("topmostSubform[0].Page2[0].p2_cb01[3]", "4");
form.setField("topmostSubform[0].Page2[0].p2_cb01[4]", "5");
form.setField("topmostSubform[0].Page2[0].p2_cb01[5]", "6");
stamper.close();
reader.close();
}
现在,所有复选框均已选中。参见f8966_filled.pdf:
当然:作为人类,我们知道我们不应该这样做,因为我们应该将字段视为单选按钮,但是AcroForm描述中没有技术原因为什么我们不能这样做。阻止我们这样做的逻辑仅出现在XFA描述中。
如果可以丢弃XFA部分,则可以解决您的问题。如果可以展平表格的话,也可以解决您的问题,在这种情况下,您应该添加以下内容:
stamper.setFormFlattening(true);
如果上述选项 Not Acceptable ,则不应丢弃XFA部分,而应按照上述说明填写AcroForm部分,并使用iText提取XML数据集(请参见第一个屏幕截图中的
datasets
),将其更新美国政府希望您进行更新的方式,并使用iText将更新数据集放回datasets
对象中。ew ...这是我在StackOverflow上写的最长答案之一。