修改LiveCycle XFA PDF脚本不破坏权限及表单填充方法咨询
问题描述
我需要填充由LiveCycle生成的XFA PDF表单,先后尝试过PDFBox 3.0.0-beta1、iText 4.2.0和PDFBox 2.0.28,均未成功。对PDF的任何修改都会导致表单无法正常使用,推测是破坏了使用权限。
我的Java修改代码如下:
PDDocument doc = Loader.loadPDF(new File(Paths.get(FileUtils.listFiles(new File("formulare"), new PrefixFileFilter("F1129"), null).toArray()[0].toString()).toUri())); PDDocumentCatalog catalog = doc.getDocumentCatalog(); PDAcroForm acroForm = catalog.getAcroForm(); PDXFAResource xfa1 = acroForm.getXFA(); COSStream cosout = doc.getDocument().createCOSStream(); OutputStream out = cosout.createRawOutputStream(); TransformerFactory tFactory = TransformerFactory.newInstance(); Transformer transformer = tFactory.newTransformer(); StreamResult result = new StreamResult(out); Document src2 = acroForm.getXFA().getDocument(); NodeList dataElements = src2.getElementsByTagName("script"); if (dataElements != null) { for (int i = 0; i < dataElements.getLength(); i++) { if (i == 45) { dataElements.item(i).setTextContent(dataElements.item(i).getTextContent() + "csDataTool.GetInstance().ExecuteImport();"); } } } transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8"); transformer.setOutputProperty(OutputKeys.INDENT, "no"); transformer.transform(new DOMSource(src2), result); PDXFAResource xfaout = new PDXFAResource(cosout); acroForm.setXFA(xfaout); out.close(); FileOutputStream fos = new FileOutputStream("f1129Modified.pdf"); doc.saveIncremental(fos); doc.close(); cosout.close(); fos.flush(); fos.close();
我尝试修改第45个<script>节点的内容,添加导入数据的代码,但修改后PDF能正常打开却无法进行任何操作,无错误或警告;但如果仅执行dataElements.item(i).setTextContent(dataElements.item(i).getTextContent());(即复制原内容),则完全正常。
另外,待导入的XML标签与我在XFA中找到的XSD不匹配,但使用Adobe Reader PRO操作一切正常。待导入XML示例:
<?xml version="1.0"?> <f1129 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="mfp:anaf:dgti:f1129:declaratie:v1" xmlns="mfp:anaf:dgti:f1129:declaratie:v1" versiune_pdf="A2.0.21" d_rec="0" suma_control="3644129" total_opm="245.5" nr_inregistrari="1" luna_r="12" an="2022" data_document="19.12.2022" nr_document="1234567890" nume_ip="asdasdas" adresa_ip="asddas" cui_ip="3643884" tip_ent="1"> <rand_op nr_op="32" iban_platitor="RO38TREZ24A670503200109X" den_trezorerie="TREZORERIA STATULUI" cod_program="0000000000" cod_angajament="AAAFSF23N4X" ind_angajament="AA2" cui_beneficiar="17460640" den_beneficiar="Your Consulting SRL" iban_beneficiar="RO38TREZ24A670503200109X" den_banca_trez="TREZORERIA STATULUI" suma_op="245.5" explicatii="asdasd" /> </f1129>
解决方案
1. 修改JavaScript是否可行?
不行。LiveCycle生成的XFA表单通常带有Adobe的完整性校验机制,会验证XFA数据包的内容哈希或签名。你的测试也证明:仅复制原脚本内容时校验通过,一旦修改内容(哪怕只是添加一行代码),校验就会失败,导致表单功能锁定。这种权限校验嵌入在XFA数据包或PDF的扩展属性中,开源库很难绕过。
2. 替代的表单填充方案
方案1:直接导入XML数据到XFA节点
既然Adobe Reader PRO能正常处理你的XML,说明表单内置了兼容逻辑,无需修改脚本触发导入,直接将XML数据写入XFA的数据集节点即可:
PDDocument doc = Loader.loadPDF(new File("formulare/F1129.pdf")); PDAcroForm acroForm = doc.getDocumentCatalog().getAcroForm(); Document xfaDoc = acroForm.getXFA().getDocument(); // 解析待导入的XML数据 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setNamespaceAware(true); Document importDoc = factory.newDocumentBuilder().parse(new File("your-data.xml")); Node importedData = xfaDoc.importNode(importDoc.getDocumentElement(), true); // 找到XFA中的数据节点(根据实际结构调整,通常在<xfa:datasets>下) NodeList datasetsList = xfaDoc.getElementsByTagName("xfa:datasets"); if (datasetsList.getLength() > 0) { Node datasets = datasetsList.item(0); // 替换原有数据节点或添加新节点 Node existingData = datasets.getFirstChild(); if (existingData != null) { datasets.replaceChild(importedData, existingData); } else { datasets.appendChild(importedData); } } // 重新序列化XFA并保存 COSStream cosout = doc.getDocument().createCOSStream(); try (OutputStream out = cosout.createRawOutputStream()) { Transformer transformer = TransformerFactory.newInstance().newTransformer(); transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8"); transformer.setOutputProperty(OutputKeys.INDENT, "no"); transformer.transform(new DOMSource(xfaDoc), new StreamResult(out)); acroForm.setXFA(new PDXFAResource(cosout)); // 尝试完整保存而非增量保存,避免权限校验冲突 doc.save("filled-form.pdf"); } finally { doc.close(); }
方案2:使用Adobe官方工具
如果开源库无法绕过校验,可使用Adobe LiveCycle ES API或Acrobat SDK,这些工具原生支持XFA表单的修改与填充,不会触发权限问题。
方案3:尝试忽略PDF安全处理
部分场景下,设置PDFBox忽略安全handler可能有效,但对XFA的特殊权限未必生效:
doc.setSecurityHandler(null);
3. XML与XSD不匹配的问题
Adobe Reader PRO能正常处理,说明表单的JavaScript有容错逻辑(如忽略额外属性、自动映射字段),无需修改XSD,直接按现有XML格式导入即可,重点保证数据层级和字段名与表单预期一致。
内容的提问来源于stack exchange,提问作者AurysVrV

