使用iText从pdf文件读取json时出错

时间:2020-02-06 06:43:00

标签: android json itext gson

我一直在尝试从pdf文件中读取JSON。我可以将JSON字符串写入pdf,但是当我阅读pdf时,出现如下错误。

原因:com.google.gson.stream.MalformedJsonException:未终止 第60行第3列的对象$ .All_Routes [0] .route_data

我在写入文件之前先打印了JSON,然后使用JSON验证程序对其进行在线验证,并且它是有效的JSON ,但是当我写入到pdf后,它变成了无效。我只是从pdf复制了JSON并在线进行了验证,但未验证并给出了错误。

这是将JSON写入pdf文件的代码。

try {
    File file = AppUtils.createFile(".pdf");
    Document document = new Document();
    document.setPageSize(PageSize.A4);
    document.addCreationDate();
    document.addAuthor("Me");
    PdfWriter.getInstance(document, new FileOutputStream(file));
    document.open();

    String jsonBody = new Gson().toJson(backUpModel);

    Gson gson = new GsonBuilder().setPrettyPrinting().create();
    JsonParser parser = new JsonParser();
    JsonElement jsonElement = parser.parse(jsonBody);
    String prettyJsonBody = gson.toJson(jsonElement);

    Log.i(Constants.TAG, "Input Json: " + prettyJsonBody);
    document.add(new Paragraph(prettyJsonBody));
    document.close();

    //Toast.makeText(BackUp.this, "Saved Succesfully", Toast.LENGTH_SHORT).show();
} catch (Exception e) {
    e.printStackTrace();
}

这是读取PDF文件的代码。

try {
    File exportDir = new File(Environment.getExternalStorageDirectory(), Constants.TAG);
    String filePath = exportDir.getPath() + File.separator + getFileName(fileUri);
    PdfReader pdfReader = new PdfReader(filePath);
    int numberOfPages = pdfReader.getNumberOfPages();
    StringBuilder stringBuilder = new StringBuilder();
    for (int i = 1; i <= numberOfPages; i++) {
        stringBuilder.append(PdfTextExtractor.getTextFromPage(pdfReader, i));
    }
    pdfReader.close();
    String jsonBody = stringBuilder.toString();
    BackUpModel backUpModel = new Gson().fromJson(jsonBody, BackUpModel.class);
} catch (IOException e) {
    e.printStackTrace();
}

有人可以建议我解决此问题的解决方案吗?

谢谢

1 个答案:

答案 0 :(得分:1)

将输入json与输出进行比较,很明显,您无法如实地从当前代码生成的PDF中提取json。

在将字符串呈现为PDF时添加换行符以防止文本碰到页边距时会出现问题。结果中的每个换行符可能已经在输入字符串中,或​​者可能已被iText引入,通常情况下无法识别。

如果iText在名称或值之外在空格或标点符号(冒号,逗号,方括号) 处换行,则这些额外的换行符不会改变json对象的含义,但换行在名称和值中打断是另一回事。

即使我们可以假设名称或值中没有任何换行符(实际上,您共享的json中的值也有换行符,但是由于您共享它的方式,这些换行符可能已经隐瞒了),因此,我们可以简单地删除它们,其中一些换行符已应用到原始值中有空格的地方,而另一些则没有。在空格处折断一行的位置,该空格将被丢弃,并且不再出现在最终输出中。同样,通常只有手头提取的输出是无法识别的。

因此,忠实的提取是不可能的。


因此,您必须更改将json嵌入PDF的方式。正如您没有提到为什么要这样做以及有什么其他选择那样,我无法给出最终的建议,仅提出一些可能与您的要求不符的方案:

  • 不是将json嵌入常规的静态页面内容,而是将其嵌入到多行表单文本字段的值中。表单字段中的值可以如实地从PDF中提取。
  • 除了页面内容中可见的json外,还将json嵌入到PDF的私有流对象中;然后您可以从该流对象中忠实地提取json。
  • 使用的字体大小应小到在渲染过程中iText都不会添加换行符。 (不过,如果不放大,结果很可能太小而无法阅读。)
  • 手动渲染json(使用低级iText API),并以某种方式标记添加的换行符和空格。在提取过程中,您必须对这些标记物做出反应。

例如,要实现选项1,将json嵌入为多行表单文本字段的值,只需将其添加如下:

Document document = new Document();
document.setPageSize(PageSize.A4);
document.addCreationDate();
document.addAuthor("Me");
PdfWriter pdfWriter = PdfWriter.getInstance(document, new FileOutputStream(jsonPdfFile));
document.open();
pdfWriter.getAcroForm().setNeedAppearances(true);
TextField textField = new TextField(pdfWriter, document.getPageSize(), "json");
textField.setOptions(TextField.MULTILINE | TextField.READ_ONLY);
PdfFormField field = textField.getTextField();
field.setValueAsString(originalJson);
pdfWriter.addAnnotation(field);
document.close();

并再次像这样提取它:

PdfReader pdfReader = new PdfReader(jsonPdfFile.getAbsolutePath());
String jsonBody = pdfReader.getAcroFields().getField("json");
pdfReader.close();

ExtractJson测试testJsonToPdfToJsonFormField

我正在使用当前的iText 5.5.14-SNAPSHOT开发分支。但是,该代码应可与任何5.5.x版本一起使用。