Как разобрать поля из акроформы PDF на основе меток в фактическом pdf с помощью IText7?

Мне нужно проанализировать заполненную налоговую форму США. Используя Itext Acroform, я могу получить все имена полей, которые у него есть, используя следующий код:


public static void main()
{
 PdfReader pdfReader = new PdfReader(src);
 PdfDocument pdfDocument = new PdfDocument(pdfReader); 

var form = PdfAcroForm.GetAcroForm(pdfDocument, false);
if (form != null)
{
        IDictionary formfields = form.GetFormFields();
                
        foreach (var field in formfields.Keys)
        {
                    
                    
          Console.WriteLine(formfields[field].GetFieldName().ToString() + ": " + formfields[field]?.GetValueAsString());
                    
        }
}
            

            
 Console.ReadLine();
}

Вывод в консоли следующий:


topmostSubform[0]:
topmostSubform[0].Page1[0]:
topmostSubform[0].Page1[0].FilingStatus[0]:
topmostSubform[0].Page1[0].FilingStatus[0].c1_01[0]: 3
topmostSubform[0].Page1[0].FilingStatus[0].c1_01[1]: 3
topmostSubform[0].Page1[0].FilingStatus[0].c1_01[2]: 3
topmostSubform[0].Page1[0].FilingStatus[0].c1_01[3]: 3
topmostSubform[0].Page1[0].FilingStatus[0].c1_01[4]: 3
topmostSubform[0].Page1[0].FilingStatus[0].f1_01[0]: Sarah expat
topmostSubform[0].Page1[0].f1_02[0]: Brian
topmostSubform[0].Page1[0].f1_03[0]: Expat
topmostSubform[0].Page1[0].YourSocial_ReadOrderControl[0]:
topmostSubform[0].Page1[0].YourSocial_ReadOrderControl[0].f1_04[0]: 239402830
topmostSubform[0].Page1[0].YourSocial_ReadOrderControl[0].f1_05[0]: Sarah
topmostSubform[0].Page1[0].YourSocial_ReadOrderControl[0].f1_06[0]: Expat
topmostSubform[0].Page1[0].ReadOrderControl[0]:
topmostSubform[0].Page1[0].ReadOrderControl[0].f1_07[0]: 234745745
topmostSubform[0].Page1[0].ReadOrderControl[0].Address[0]:
topmostSubform[0].Page1[0].ReadOrderControl[0].Address[0].f1_08[0]: 100 Main Road
topmostSubform[0].Page1[0].ReadOrderControl[0].Address[0].f1_09[0]: 456
topmostSubform[0].Page1[0].ReadOrderControl[0].Address[0].f1_10[0]: Bangkok
topmostSubform[0].Page1[0].ReadOrderControl[0].Address[0].f1_11[0]: Thailand
topmostSubform[0].Page1[0].ReadOrderControl[0].Address[0].f1_12[0]: Bangkok
topmostSubform[0].Page1[0].ReadOrderControl[0].Address[0].f1_13[0]: 78945312
topmostSubform[0].Page1[0].ReadOrderControl[1]:
topmostSubform[0].Page1[0].ReadOrderControl[1].PresidentialElection[0]:
topmostSubform[0].Page1[0].ReadOrderControl[1].PresidentialElection[0].c1_02[0]: 1
topmostSubform[0].Page1[0].ReadOrderControl[1].PresidentialElection[0].c1_03[0]: 1
topmostSubform[0].Page1[0].ReadOrderControl[1].StandardDeduction[0]:
topmostSubform[0].Page1[0].ReadOrderControl[1].StandardDeduction[0].c1_04[0]: 1
topmostSubform[0].Page1[0].ReadOrderControl[1].StandardDeduction[0].c1_05[0]: 1
topmostSubform[0].Page1[0].ReadOrderControl[1].StandardDeduction[0].c1_06[0]: 1
topmostSubform[0].Page1[0].ReadOrderControl[1].AgeBlindness[0]:
topmostSubform[0].Page1[0].ReadOrderControl[1].AgeBlindness[0].c1_07[0]: 1
topmostSubform[0].Page1[0].ReadOrderControl[1].AgeBlindness[0].c1_08[0]: 1
topmostSubform[0].Page1[0].ReadOrderControl[1].AgeBlindness[0].c1_09[0]: 1
topmostSubform[0].Page1[0].ReadOrderControl[1].AgeBlindness[0].c1_10[0]: 1
topmostSubform[0].Page1[0].IfMoreThanFour[0]:
topmostSubform[0].Page1[0].IfMoreThanFour[0].c1_11[0]: 1
topmostSubform[0].Page1[0].Dependents[0]:
topmostSubform[0].Page1[0].Dependents[0].Table_Dependents[0]:
topmostSubform[0].Page1[0].Dependents[0].Table_Dependents[0].Row1[0]:
topmostSubform[0].Page1[0].Dependents[0].Table_Dependents[0].Row1[0].f1_14[0]: Kevin                                               Expat
topmostSubform[0].Page1[0].Dependents[0].Table_Dependents[0].Row1[0].f1_15[0]: 123871928
topmostSubform[0].Page1[0].Dependents[0].Table_Dependents[0].Row1[0].f1_16[0]: Son
topmostSubform[0].Page1[0].Dependents[0].Table_Dependents[0].Row1[0].c1_12[0]: 1
topmostSubform[0].Page1[0].Dependents[0].Table_Dependents[0].Row1[0].c1_13[0]: 2
topmostSubform[0].Page1[0].Dependents[0].Table_Dependents[0].Row2[0]:
topmostSubform[0].Page1[0].Dependents[0].Table_Dependents[0].Row2[0].f1_17[0]: Audra                                              Expat
topmostSubform[0].Page1[0].Dependents[0].Table_Dependents[0].Row2[0].f1_18[0]: 123718237
topmostSubform[0].Page1[0].Dependents[0].Table_Dependents[0].Row2[0].f1_19[0]: Daughter
topmostSubform[0].Page1[0].Dependents[0].Table_Dependents[0].Row2[0].c1_14[0]: 1
topmostSubform[0].Page1[0].Dependents[0].Table_Dependents[0].Row2[0].c1_15[0]: 2
topmostSubform[0].Page1[0].Dependents[0].Table_Dependents[0].Row3[0]:
topmostSubform[0].Page1[0].Dependents[0].Table_Dependents[0].Row3[0].f1_20[0]:
topmostSubform[0].Page1[0].Dependents[0].Table_Dependents[0].Row3[0].f1_21[0]:
topmostSubform[0].Page1[0].Dependents[0].Table_Dependents[0].Row3[0].f1_22[0]:
topmostSubform[0].Page1[0].Dependents[0].Table_Dependents[0].Row3[0].c1_16[0]: 1
topmostSubform[0].Page1[0].Dependents[0].Table_Dependents[0].Row3[0].c1_17[0]: 2
topmostSubform[0].Page1[0].Dependents[0].Table_Dependents[0].Row4[0]:
topmostSubform[0].Page1[0].Dependents[0].Table_Dependents[0].Row4[0].f1_23[0]:
topmostSubform[0].Page1[0].Dependents[0].Table_Dependents[0].Row4[0].f1_24[0]:
topmostSubform[0].Page1[0].Dependents[0].Table_Dependents[0].Row4[0].f1_25[0]:
topmostSubform[0].Page1[0].Dependents[0].Table_Dependents[0].Row4[0].c1_18[0]: 1
topmostSubform[0].Page1[0].Dependents[0].Table_Dependents[0].Row4[0].c1_19[0]: 2
topmostSubform[0].Page1[0].ReadOrderControl_Lns1-8b[0]:
topmostSubform[0].Page1[0].ReadOrderControl_Lns1-8b[0].f1_26[0]: 123,828.
topmostSubform[0].Page1[0].ReadOrderControl_Lns1-8b[0].f1_27[0]: 5,589.
topmostSubform[0].Page1[0].ReadOrderControl_Lns1-8b[0].f1_28[0]: 1,000.
topmostSubform[0].Page1[0].ReadOrderControl_Lns1-8b[0].f1_29[0]: 4,789.
topmostSubform[0].Page1[0].ReadOrderControl_Lns1-8b[0].f1_30[0]: 1,485.
topmostSubform[0].Page1[0].ReadOrderControl_Lns1-8b[0].f1_31[0]: 1,200.
topmostSubform[0].Page1[0].ReadOrderControl_Lns1-8b[0].f1_32[0]: 41,885.
topmostSubform[0].Page1[0].ReadOrderControl_Lns1-8b[0].f1_33[0]: 1,300.
topmostSubform[0].Page1[0].ReadOrderControl_Lns1-8b[0].f1_34[0]: 45,895.
topmostSubform[0].Page1[0].ReadOrderControl_Lns1-8b[0].f1_35[0]: 1,965.
topmostSubform[0].Page1[0].ReadOrderControl_Lns1-8b[0].f1_36[0]: 50,145.
topmostSubform[0].Page1[0].ReadOrderControl_Lns1-8b[0].c1_20[0]: 1
topmostSubform[0].Page1[0].ReadOrderControl_Lns1-8b[0].f1_37[0]: 7,894.
topmostSubform[0].Page1[0].ReadOrderControl_Lns1-8b[0].f1_38[0]: 8,654.
topmostSubform[0].Page1[0].ReadOrderControl_Lns1-8b[0].f1_39[0]: 50,928.
topmostSubform[0].Page1[0].ReadOrderControl_Lns1-8b[0].f1_40[0]: 8,956.
topmostSubform[0].Page1[0].ReadOrderControl_Lns1-8b[0].f1_41[0]: 50,299.
topmostSubform[0].Page1[0].f1_42[0]: 24,000.
topmostSubform[0].Page1[0].f1_43[0]: 25,895.
topmostSubform[0].Page1[0].f1_44[0]: 47,568.
topmostSubform[0].Page1[0].f1_45[0]: 26,299.
topmostSubform[0].Page2[0]:
topmostSubform[0].Page2[0].Lines12a-12b_ReadOrder[0]:
topmostSubform[0].Page2[0].Lines12a-12b_ReadOrder[0].c2_01[0]:
topmostSubform[0].Page2[0].Lines12a-12b_ReadOrder[0].c2_02[0]:
topmostSubform[0].Page2[0].Lines12a-12b_ReadOrder[0].c2_03[0]: 1
topmostSubform[0].Page2[0].Lines12a-12b_ReadOrder[0].f2_01[0]: 5,786
topmostSubform[0].Page2[0].Lines12a-12b_ReadOrder[0].f2_02[0]:
topmostSubform[0].Page2[0].f2_03[0]: 5,786.
topmostSubform[0].Page2[0].Lines13a-13b_ReadOrder[0]:
topmostSubform[0].Page2[0].Lines13a-13b_ReadOrder[0].f2_04[0]: 4,000.
topmostSubform[0].Page2[0].f2_05[0]: 4,301.
topmostSubform[0].Page2[0].f2_06[0]: 1,485.
topmostSubform[0].Page2[0].f2_07[0]: 1,229.
topmostSubform[0].Page2[0].f2_08[0]: 2,714.
topmostSubform[0].Page2[0].f2_09[0]: 4,856.
topmostSubform[0].Page2[0].Line18_ReadOrder[0]:
topmostSubform[0].Page2[0].Line18_ReadOrder[0].f2_10[0]: 85,475.
topmostSubform[0].Page2[0].Line18_ReadOrder[0].f2_11[0]: 95,478
topmostSubform[0].Page2[0].Line18_ReadOrder[0].f2_12[0]: 20,000.
topmostSubform[0].Page2[0].Line18_ReadOrder[0].f2_13[0]: 89,540.
topmostSubform[0].Page2[0].f2_14[0]: 45,569.
topmostSubform[0].Page2[0].f2_15[0]: 47,520.
topmostSubform[0].Page2[0].f2_16[0]: 54,565.
topmostSubform[0].Page2[0].c2_04[0]: 1
topmostSubform[0].Page2[0].f2_17[0]: 4,000.
topmostSubform[0].Page2[0].RoutingNo[0]:
topmostSubform[0].Page2[0].RoutingNo[0].f2_18[0]: 123456778
topmostSubform[0].Page2[0].c2_05[0]: 1
topmostSubform[0].Page2[0].c2_05[1]: 1
topmostSubform[0].Page2[0].AccountNo[0]:
topmostSubform[0].Page2[0].AccountNo[0].f2_19[0]: 23455789900112586
topmostSubform[0].Page2[0].f2_20[0]: 85,000.
topmostSubform[0].Page2[0].f2_21[0]: 2,714.
topmostSubform[0].Page2[0].f2_22[0]: 55,000.
topmostSubform[0].Page2[0].ThirdPartyDesignee[0]:
topmostSubform[0].Page2[0].ThirdPartyDesignee[0].c2_06[0]: 1
topmostSubform[0].Page2[0].ThirdPartyDesignee[0].c2_06[1]: 1
topmostSubform[0].Page2[0].ThirdPartyDesignee[0].f2_23[0]: XYZ
topmostSubform[0].Page2[0].ThirdPartyDesignee[0].f2_24[0]: 78954231321
topmostSubform[0].Page2[0].ThirdPartyDesignee[0].f2_25[0]: 12131
topmostSubform[0].Page2[0].Signatures[0]:
topmostSubform[0].Page2[0].Signatures[0].f2_26[0]: SD
topmostSubform[0].Page2[0].Signatures[0].f2_27[0]: 123456
topmostSubform[0].Page2[0].Signatures[0].f2_28[0]: SD
topmostSubform[0].Page2[0].Signatures[0].f2_29[0]: 324324
topmostSubform[0].Page2[0].Signatures[0].f2_30[0]: 784561358922
topmostSubform[0].Page2[0].Signatures[0].f2_31[0]: [email protected]
topmostSubform[0].Page2[0].PaidPreparer[0]:
topmostSubform[0].Page2[0].PaidPreparer[0].Preparer[0]:
topmostSubform[0].Page2[0].PaidPreparer[0].Preparer[0].f2_32[0]: SSDS
topmostSubform[0].Page2[0].PaidPreparer[0].Preparer[0].f2_33[0]: 5454745
topmostSubform[0].Page2[0].PaidPreparer[0].Preparer[0].CheckIf[0]:
topmostSubform[0].Page2[0].PaidPreparer[0].Preparer[0].CheckIf[0].c2_07[0]: 1
topmostSubform[0].Page2[0].PaidPreparer[0].Preparer[0].CheckIf[0].c2_07[1]: 1
topmostSubform[0].Page2[0].PaidPreparer[0].Preparer[0].f2_34[0]: SDSDE
topmostSubform[0].Page2[0].PaidPreparer[0].Preparer[0].f2_35[0]: 8787922313
topmostSubform[0].Page2[0].PaidPreparer[0].Preparer[0].f2_36[0]: SDSDSD
topmostSubform[0].Page2[0].PaidPreparer[0].Preparer[0].f2_37[0]: 646464

То, что я ожидаю разобрать, выглядит примерно так:


...
...
"First Name": "Sarah",
"Last Name":"Expat"
...
...

Проблема здесь в том, что эти поля в фактическом выводе являются резкими и не имеют отношения к фактической метке формы, значение которой сопоставляется.

Например, topmostSubform[0].Page1[0].FilingStatus[0].f1_01[0]: Sarah expat, здесь по форме это значение на самом деле является именем. Но нет доступного сопоставления, которое представляет f1_01[0] как имя. Одним из способов является ручное сопоставление, при котором я вручную пишу код для сопоставления этого с каждой меткой в ​​​​форме. Но структура, позиционирование и маркировка одних и тех же форм из года в год меняются. Таким образом, если мы пойдем с ручным картированием, то это приведет нас к ручному картированию за все годы для всех форм (что является громоздким процессом).

Следовательно, возможно ли вообще каким-то образом получить взаимосвязь между метками и их значениями из проанализированных данных, которые у нас есть в акроформе, без ручного сопоставления (автоматически?)?. Я также рассмотрел возможность преобразования акроформы в XFAForm и создания из нее XML, но та же проблема: у нас нет сопоставления между метками и их соседними значениями.

Редактировать Определение сопоставления вручную, конечно, возможно, но, как упоминалось ранее, нам придется вручную определять сопоставление для каждой формы для каждого года, а это трудоемкий процесс. Поскольку форма acro внизу также содержит XFA, содержит ли IRS своего рода файл определения сопоставления? Или есть автоматический способ выяснить связь между данными и их меткой (формы)?


person Karan Desai    schedule 23.09.2020    source источник
comment
Следовательно, возможно ли вообще как-то извлечь взаимосвязь между метками и их значениями из проанализированных данных, которые у нас есть в акроформе? - не совсем точно для произвольных документов и автоматической обработки. Достаточно точно, если человек быстро проверит установленное отображение.   -  person mkl    schedule 24.09.2020
comment
Спасибо за ответ @mkl, да, конечно, это возможность вручную определить сопоставление, как указано в вопросе, нам пришлось бы вручную определять сопоставление для каждой формы для каждого года, что является трудоемким процессом. Поскольку acroform также содержит xfa, содержит ли IRS своего рода файл определения сопоставления? Или есть ли какой-либо автоматический способ выяснить связь между данными и их меткой (формы)? (Редактирование моего вопроса, чтобы добавить этот вопрос для ясности)   -  person Karan Desai    schedule 24.09.2020
comment
Наличие определения формы XFA под может помочь, но (как вы можете прочитать в ответе Яна для поля f1_01, которое вы использовали в качестве примера) даже там у вас нет меток все время. Кроме того, нет никакой гарантии, что вы и дальше будете находить определения XFA в будущих формах, ведь дополнительные XFA в PDF-файлах устарели несколько лет назад. Таким образом, автоматический анализ формы (AcroForm или XFA) может помочь начать сопоставление, но вам все равно понадобится человек для проверки и заполнения недостающей информации.   -  person mkl    schedule 24.09.2020


Ответы (1)


Это не полный ответ, но я думаю, может дать некоторые идеи, как решить такую ​​​​проблему:

Документ представляет собой статическую форму XFA, в которую встроены как AcroForm, так и пакет XFA.

Обе вещи логически связаны друг с другом. Поэтому, если вы можете сопоставить поле AcroForm с узлами шаблона в пакете XFA, вы можете использовать элемент <caption> для сбора информации о метке. Например, то, что вы ожидаете, поскольку фамилия привязана к полю topmostSubform[0].Page1[0].FilingStatus[0].f1_03[0], которое можно сопоставить с этим определением XML:

введите здесь описание изображения

Но поле, которое вы использовали в качестве примера (topmostSubform[0].Page1[0].FilingStatus[0].f1_01[0]), к сожалению, вообще не имеет заголовка, но вы можете попробовать использовать там элемент <assist>:

введите здесь описание изображения

В конце вы все равно должны проверить эти сопоставления, потому что они также могут измениться в будущем, но это может дать вам хотя бы некоторые подсказки.

Я понятия не имею, можете ли вы получить доступ к этому сопоставлению в iText и как это сделать.

person Jan Slabon    schedule 24.09.2020
comment
Ох! Внутри каждого тега поля могут быть либо вспомогательные теги, либо теги заголовка, либо их может не быть. Это определенно дает мне правильное направление для изучения, и я могу попробовать автоматизировать себя, используя этот шаблон, который вы мне только что показали. Спасибо :) - person Karan Desai; 24.09.2020