我一直在使用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]。此类字段字典是的不同表示形式,同一字段则应具有相同的值。

有两种选择:

  • 如果您的PDF的字段字典的名称(topmostSubform[0].Page2[0].p2_cb01[0])具有不同的值,则您没有有效的PDF文件:它违反了ISO-32000-1,这是官方的PDF规范。
  • 也许您认为您有具有相同字段名称和不同值的复选框,但实际上这些复选框实际上是具有不同单选按钮的单选字段。也许您没有使用正确的值。也许还有其他事情在起作用。为了使SO读者能够为您提供帮助,他需要查看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]的值上的0topmostSubform[0].Page2[0].p2_cb01[1]的是1,依此类推。不是... topmostSubform[0].Page2[0].p2_cb01[0]值为1topmostSubform[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上写的最长答案之一。

    09-05 05:41