如何使用iText和Java检查具有相同变量名称的PDF文件中的复选框

Jos*_*des 6 java pdf itext

我一直在使用iTextJava来自动填写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");
Run Code Online (Sandbox Code Playgroud)

拜托,我需要建议.

Bru*_*gie 4

请允许我引用 ISO-32000-1 第 12.7.3.2 节“字段名称”:

如果不同的字段字典是具有该名称的共同祖先的后代并且没有自己的部分字段名称(T 条目),则不同的字段字典可能具有相同的完全限定字段名称。这样的字段字典是同一底层字段的不同表示;它们应该仅在指定其视觉外观的属性上有所不同。特别是,具有相同完全限定字段名称的字段字典应具有相同的字段类型(FT)、值(V)和默认值(DV)。

如果我们将其应用于您的问题:不同的字段字典可能具有相同的名称topmostSubform[0].Page2[0].p2_cb01[0]。这些字段字典是同一字段的不同表示,并且它们应具有相同的值。

有两种选择:

  1. 如果您的 PDF 中的字段字典的名称 ( topmostSubform[0].Page2[0].p2_cb01[0]) 具有不同的值,则您没有有效的 PDF 文件:它违反了官方 PDF 规范 ISO-32000-1。
  2. 也许您认为您有具有相同字段名称和不同值的复选框,但也许这些复选框实际上是具有不同单选按钮的单选字段。也许您没有使用正确的值。也许还有其他因素在起作用。为了让 SO 读者能够帮助您,他需要查看 PDF 文件。

如果选项 1 适用,请放弃所有希望:您的 PDF 很糟糕。修复它或扔掉它。如果选项 2 适用,请共享 PDF。

检查 PDF 文件后更新:

选项 2 适用。您有一个混合表单,这意味着该表单在 PDF 中描述了两次,一次使用 AcroForm 技术,一次使用 XFA。请首先阅读我对以下问题的回答:PDFTK 和删除 XFA 格式

当您在 Adob​​e Reader 中打开 PDF 时,您会注意到这些字段就像单选按钮一样。当您单击一个时,它会被选中,但是当您单击另一个时,它会被选中,但第一个不再被选中。

您看到的是 XFA 中描述的表单,XFA 表单和 AcroForm 描述之间存在一些重要的区别。这不是一个错误。这是混合形式所固有的。

当您使用以下方式填写表格时:

form.setField("topmostSubform[0].Page2[0].p2_cb01[0]", "1");
Run Code Online (Sandbox Code Playgroud)

iText 正确填写了 AcroForm,但无法填写 XFA 表单,因为 iText 对 XFA 流(实际上以 XML 表示)中应设置相应值的位置进行了有根据的猜测(不是准确的猜测)。有关更多详细信息: iText in Action - 第二版第8 章对此进行了解释。

在这种情况下,我通常所做的正是询问是否可以安全地丢弃 XFA 部分的人所做的:我删除了 XFA 部分:

AcroFields form = stamper.getAcroFields();
form.removeXfa();
Run Code Online (Sandbox Code Playgroud)

这极大地简化了事情,但它还没有解决你的问题。为了解决您的问题,我们需要查看 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]
Run Code Online (Sandbox Code Playgroud)

现在让我们看看这些字段的内部。

这是字段topmostSubform[0].Page2[0].p2_cb01[0]

在此输入图像描述

这是字段topmostSubform[0].Page2[0].p2_cb01[0]

在此输入图像描述

这些是 AcroForm 复选框,但有一条供人类使用的说明:仅选择一个。该指令只能由人类理解,而不能由机器或软件理解。

我第一次尝试编写FillHybridForm示例失败了,因为我犯了与您类似的错误。我没有仔细观察不同的外观状态。我认为is的On值是,等等。它不是... is的On值,is 的 On值,等等。topmostSubform[0].Page2[0].p2_cb01[0]0topmostSubform[0].Page2[0].p2_cb01[1]1topmostSubform[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();
}
Run Code Online (Sandbox Code Playgroud)

现在所有复选框均已选中。请参阅f8966_filled.pdf

在此输入图像描述

当然:作为人类,我们知道我们不应该这样做,因为我们应该将这些字段视为单选按钮,但 AcroForm 描述中没有任何技术原因说明我们不能这样做。阻止我们这样做的逻辑仅存在于 XFA 描述中。

如果可以接受丢弃 XFA 部分,这可以解决您的问题。如果可以展平表单,它也可以解决您的问题,在这种情况下您应该添加:

stamper.setFormFlattening(true);
Run Code Online (Sandbox Code Playgroud)

如果上述选项不可接受,则不应丢弃 XFA 部分,而应按照上述方式填写 AcroForm 部分,并使用 iText 提取 XML 数据集(请参见datasets第一个屏幕截图),按以下方式更新它美国政府希望您更新它,并使用 iText 将更新数据集放回到对象中datasets

唷……这是我在 StackOverflow 上写过的最长的答案之一。

  • 它是一种混合 XFA 形式。这意味着您同时拥有 AcroForm 和 XFA 表单。这总是让事情变得复杂。但乍一看,好像你犯了一个错误。我会看看是否可以创建一个代码示例来向您展示哪里出了问题。 (2认同)