2017-01-06 12 views
3

안녕하십니까. 나는 누군가가이 주제에 관해 나를 도울 수 있기를 바라고있다. 작년에 나는 iTextSharp을 사용하여 VB.NET 프로그램을 설정했다. 여기서 사용자는 I9를 채우기 위해 정보를 입력 할 수 있었고 그 정보는 PDF를 채우고 인쇄했다. 새로운 I9에서는 알 수없는 어려움을 겪고 있습니다.자동 채우기 I-9 PDF XFA 양식

먼저 코드는 오류가 발생하지 않습니다. 채워진 양식 대신 "로드하려고하는 문서에 Adobe Reader 8 이상이 필요합니다 .Adobe Reader가 설치되어 있지 않을 수 있습니다 ..."등의 PDF가 표시되므로 결과가 좋지 않습니다. 필자는 가장 최근의 Reader 버전을 사용하여 다시 동일한 결과를 얻었습니다.

아마도 필드 이름 구조가 변경되었다고 생각하면서 처음/필드 형식으로 필드를 읽으려고 시도했습니다. (아래 코드). 그러나 지금은 읽을 필드가 없다는 것을 알려줍니다 (AcroFields.Fields.Count = 0).

Private Sub ListFieldNames(pdfTemplate As String) 
    Dim pdfTemplate As String = "c:\Temp\PDF\fw4.pdf" 
    Dim pdfReader As PdfReader = New PdfReader(pdfTemplate) 
    Dim de As KeyValuePair(Of String, iTextSharp.text.pdf.AcroFields.Item) 

    For Each de In pdfReader.AcroFields.Fields 
     Console.WriteLine(de.Key.ToString()) 
    Next 
End Sub 

따라서 일부 검색을 시작했으며 전환 할 수있는 다른 유형의 PDF 구조에 대한 참조를 발견했습니다. XFA. 솔직히 아직 만족스러운 문서/샘플을 찾지 못했지만 XFA PDF 구조에서 읽을 수있는 코드를 찾았습니다. (아래 코드). 실제로 여기에는 두 가지 방법이 있습니다. 첫 번째는 기본적으로 xfaFields에 xmlNodes가 없음을 보여줍니다. 두 번째 노드는 "데이터"라는 노드를 찾지 만 그 노드는 찾지 않지만 자식 노드는 찾지 않습니다.

Private Sub ReadXfa(pdfTemplate As String) 
    pdfReader.unethicalreading = True 
    Dim readerPDF As New PdfReader(pdfTemplate) 

    Dim xfaFields = readerPDF.AcroFields.Xfa.DatasetsSom.Name2Node 

    For Each xmlNode In xfaFields 
     Console.WriteLine(xmlNode.Value.Name + ":" + xmlNode.Value.InnerText) 
    Next 
    'Example of how to get a field value 
    ' Dim lastName = xfaFields.First(Function(a) a.Value.Name = "textFieldLastNameGlobal").Value.InnerText 


    Dim reader As New PdfReader(pdfTemplate) 
    Dim xfa As New XfaForm(reader) 
    Dim node As XmlNode = xfa.DatasetsNode() 
    Dim list As XmlNodeList = node.ChildNodes() 
    For i As Integer = 0 To list.Count - 1 
     Console.WriteLine(list.Item(i).LocalName()) 
     If "data".Equals(list.Item(i).LocalName()) Then 
      node = list.Item(i) 
      Exit For 
     End If 
    Next 
    list = node.ChildNodes() 
    For i As Integer = 0 To list.Count - 1 
     Console.WriteLine(list.Item(i).LocalName()) 
    Next 
    reader.Close() 
End Sub 

https://www.uscis.gov/system/files_force/files/form/i-9.pdf?download=1

위의 링크는 정부가 제공하는 I9의 PDF로 이동합니다.

그래서 ... 여러 질문이있는 것 같습니다. 가장 간단한 방법은 누군가가이 프로세스를 수행했는지/그들이 나를 도울 수 있는지 여부입니다. 이 새로운 PDF 파일을 읽고 쓰는 방법에 관해 누군가가 올바른 방향으로 나를 안내 할 수 있다면, 그것은 엄청난 것이 될 것입니다. 솔직히 그들이 사용하는 형식의 "유형"을 결정하는 방법을 확신하지 못합니다. AcroField, XFA, 다른 것?

시간 내 주셔서 감사합니다.

답변

2

처음에는 죄송합니다. vb.net을 더 이상 사용하지 않지만 다음 코드를 변환 할 수 있어야합니다.

당신은 이미 자신이 새로운 양식이 XFA임을 알았습니다. 양식 필드와 데이터를 볼 수있는 프로그래밍 방식이 아닌 쉬운 방법이 있습니다. Adobe Reader 버전을 업그레이드 했으므로 Reader DC를 사용하고 있다고 생각했습니다.

Edit => Form Options => Export Data... 

당신이 검사 할 수있는 XML 파일로 양식을 보냅니다 메뉴 옵션에서. XML 파일은 양식을 채우기 위해 해당 XML 문서가 필요하다는 힌트를 제공합니다. 이는 AcroForm으로 작성된 양식과는 매우 다릅니다.

다음은 시작하기 쉬운 몇 가지 코드입니다.첫 번째 방법은 그것을 빈 XML 문서를 읽고 업데이트 :

public string FillXml(Dictionary<string, string> fields) 
{ 
    // XML_INFILE => physical path to XML file exported from I-9 
    XDocument xDoc = XDocument.Load(XML_INFILE); 
    foreach (var kvp in fields) 
    { 
     // handle multiple elements in I-9 form 
     var elements = xDoc.XPathSelectElements(
      string.Format("//{0}", kvp.Key) 
     ); 
     if (elements.Count() > 0) 
     { 
      foreach (var e in elements) { e.Value = kvp.Value; } 
     } 
    } 

    return xDoc.ToString(); 
} 

을 이제 우리는 유효한 XML을 만들 일부 샘플 데이터로 양식 필드를 채우는 방법을 가지고 :

var fields = new Dictionary<string, string>() 
{ 
    { "textFieldLastNameGlobal", "Doe" }, 
    { "textFieldFirstNameGlobal", "Jane" } 
}; 
var filledXml = FillXml(fields); 

using (var ms = new MemoryStream()) 
{ 
    // PDF_READER => I-9 PdfReader instance 
    using (PDF_READER) 
    { 
     // I-9 has password security 
     PdfReader.unethicalreading = true; 
     // maintain usage rights on output file 
     using (var stamper = new PdfStamper(PDF_READER, ms, '\0', true)) 
     { 
      XmlDocument doc = new XmlDocument(); 
      doc.LoadXml(filledXml); 
      stamper.AcroFields.Xfa.FillXfaForm(doc.DocumentElement); 
     } 
    } 
    File.WriteAllBytes(OUTFILE, ms.ToArray()); 
} 

하는 응답하도록 마지막 질문 양식 '유형'을 결정하는 방법, 그래서 같이 PdfReader 인스턴스를 사용

PDF_READER.AcroFields.Xfa.XfaPresent 

true가 XFA, false 수단을 의미 AcroForm.

+0

입력 해 주셔서 감사합니다. 나는 이것을 시험해보고 지금 시험해보고 결과를 업데이트 할 것이다. – Brenda

1

거기에 누군가가 그것을 사용할 수있는 경우 내 마지막 코드가 있습니다 ... i9는 말도 안되게 까다로운 양식이기 때문에 다음에 On Error Resume이 있습니다. 약간 다른 점을 약간 다르게 채우기로 선택하고 있습니다. 그들은 나를 원해. 또한 변수를 더 짧게 유지하기 위해 변수를 설정하는 부분을 다듬 었습니다. 도와 주신 kuujinbo에게 다시 한번 감사드립니다!

Private Sub ExportI9() 
    Dim pdfTemplate As String = Path.Combine(Application.StartupPath, "PDFs\2017-I9.pdf") 
    pdfTemplate = Replace(pdfTemplate, "bin\Debug\", "") 


    Dim fields = New Dictionary(Of String, String)() From { 
    {"textFieldLastNameGlobal", Me.tbLast.Text}, 
    {"textFieldFirstNameGlobal", Me.tbFirst.Text}, 
    {"textFieldMiddleInitialGlobal", Mid(Me.tbMiddle.Text, 1, 1)}, 
    {"textFieldOtherNames", Me.tbOtherName.Text}, 
    {"form1/section1Page1/subSection1PositionWrapper/subSection1Top/subEmployeeInfo/subSection1Row2/textFieldAddress", addr1}, 
    {"form1/section1Page1/subSection1PositionWrapper/subSection1Top/subEmployeeInfo/subSection1Row2/textFieldAptNum", ""}, 
    {"form1/section1Page1/subSection1PositionWrapper/subSection1Top/subEmployeeInfo/subSection1Row2/textFieldCityOrTown", city1}, 
    {"form1/section1Page1/subSection1PositionWrapper/subSection1Top/subEmployeeInfo/subSection1Row2/State", state1}, 
    {"form1/section1Page1/subSection1PositionWrapper/subSection1Top/subEmployeeInfo/subSection1Row2/textFieldZipCode", zip1}, 
    {"dateFieldBirthDate", Me.dtpBirth.Value}, 
    {"SSN", Me.tbSSN.Text}, 
    {"fieldEmail", ""}, 
    {"fieldPhoneNum", sphone}, 
    {"radioButtonListCitizenship", citizenship}, 
    {"form1/section1Page1/subSection1PositionWrapper/subSection1Bottom/subCitizenshipStatus/textFieldResidentType", alienuscis}, 
    {"dateAlienAuthDate", dauth}, 
    {"form1/section1Page1/subSection1PositionWrapper/subSection1Bottom/subAuthorizedAlien/numFormI94Admission", Me.tbi94.Text}, 
    {"numForeignPassport", Me.tbPassport.Text}, 
    {"CountryofIssuance", Me.tbPassportCountry.Text}, 
    {"numAlienOrUSCIS", usc}, 
    {"form1/section1Page1/subSection1PositionWrapper/subSection1Bottom/subAuthorizedAlien/textFieldResidentType", alienuscis}, 
    {"rbListPerparerOrTranslator", 3}, 
    {"dropdownMultiPreparerOrTranslator", 1}, 
     {"form1/section1Page1/subSection1PositionWrapper/subSection1Bottom/subPreparerTranslator/subPrepererTranslator1/subTranslatorSignature/subRow2/textFieldFirstName", prepfirst}, 
     {"form1/section1Page1/subSection1PositionWrapper/subSection1Bottom/subPreparerTranslator/subPrepererTranslator1/subTranslatorSignature/subRow2/textFieldLastName", preplast}, 
     {"form1/section1Page1/subSection1PositionWrapper/subSection1Bottom/subPreparerTranslator/subPrepererTranslator1/subTranslatorSignature/subRow3/textFieldAddress", Replace(prepadd, "#", "No. ")}, 
     {"form1/section1Page1/subSection1PositionWrapper/subSection1Bottom/subPreparerTranslator/subPrepererTranslator1/subTranslatorSignature/subRow3/textFieldCityOrTown", prepcity}, 
     {"form1/section1Page1/subSection1PositionWrapper/subSection1Bottom/subPreparerTranslator/subPrepererTranslator1/subTranslatorSignature/subRow3/State", prepstate}, 
     {"form1/section1Page1/subSection1PositionWrapper/subSection1Bottom/subPreparerTranslator/subPrepererTranslator1/subTranslatorSignature/subRow3/textFieldZipCode", prepzip}, 
    {"form1/section2and3Page2/subSection2/subVerificationListsBorder/subDocListA1/selectListA1DocumentTitle", doctitle1}, 
    {"form1/section2and3Page2/subSection2/subVerificationListsBorder/subListBandCBorder/subDocListB/selectListBDocumentTitle", doctitle2}, 
    {"form1/section2and3Page2/subSection2/subVerificationListsBorder/subListBandCBorder/subDocListC/selectListCDocumentTitle", doctitle3}, 
    {"form1/section2and3Page2/subSection2/subVerificationListsBorder/subDocListA1/textFieldIssuingAuthority", issued1}, 
    {"form1/section2and3Page2/subSection2/subVerificationListsBorder/subListBandCBorder/subDocListB/textFieldIssuingAuthority", issued2}, 
    {"form1/section2and3Page2/subSection2/subVerificationListsBorder/subListBandCBorder/subDocListC/textFieldIssuingAuthority", issued3}, 
    {"form1/section2and3Page2/subSection2/subVerificationListsBorder/subDocListA1/dateExpiration", expdate1}, 
    {"form1/section2and3Page2/subSection2/subVerificationListsBorder/subListBandCBorder/subDocListB/dateExpiration", expdate2}, 
    {"form1/section2and3Page2/subSection2/subVerificationListsBorder/subListBandCBorder/subDocListC/dateExpiration", expdate3}, 
    {"form1/section2and3Page2/subSection2/subVerificationListsBorder/subDocListA1/textFieldDocumentNumber", docnum1}, 
    {"form1/section2and3Page2/subSection2/subVerificationListsBorder/subListBandCBorder/subDocListB/textFieldDocumentNumber", docnum2}, 
    {"form1/section2and3Page2/subSection2/subVerificationListsBorder/subListBandCBorder/subDocListC/textFieldDocumentNumber", docnum3}, 
     {"form1/section2and3Page2/subSection2/subCertification/subAttest/dateEmployeesFirstDay", CDate(Me.dtpHired.Value).ToShortDateString}, 
     {"form1/section2and3Page2/subSection2/subCertification/subEmployerInformation/subEmployerInfoRow2/textFieldLastName", certlast}, 
     {"form1/section2and3Page2/subSection2/subCertification/subEmployerInformation/subEmployerInfoRow2/textFieldFirstName", certfirst}, 
     {"form1/section2and3Page2/subSection2/subCertification/subEmployerInformation/subEmployerInfoRow3/textFieldAddress", orgadd}, 
     {"form1/section2and3Page2/subSection2/subCertification/subEmployerInformation/subEmployerInfoRow3/textFieldCityOrTown", orgcity}, 
     {"form1/section2and3Page2/subSection2/subCertification/subEmployerInformation/subEmployerInfoRow3/State", orgstate}, 
     {"form1/section2and3Page2/subSection2/subCertification/subEmployerInformation/subEmployerInfoRow3/textFieldZipCode", orgzip}, 
     {"textBusinessOrgName", orgname} 
    } 


    Dim PDFUpdatedFile As String = pdfTemplate 
    PDFUpdatedFile = Replace(PDFUpdatedFile, "I9", Me.tbSSN.Text & "-I9") 
    If System.IO.File.Exists(PDFUpdatedFile) Then System.IO.File.Delete(PDFUpdatedFile) 
    Dim readerPDF As New PdfReader(pdfTemplate) 


    Dim filledXml = FillXml(fields) 
    Using ms = New MemoryStream() 
     Using readerPDF 
      ' I-9 has password security 
      PdfReader.unethicalreading = True 
      Dim stamper As New PdfStamper(readerPDF, ms, ControlChars.NullChar, True) 
      Using stamper 
       Dim doc As New XmlDocument() 
       doc.LoadXml(filledXml) 
       stamper.AcroFields.Xfa.FillXfaForm(doc.DocumentElement) 
      End Using 
     End Using 
     File.WriteAllBytes(PDFUpdatedFile, ms.ToArray()) 
    End Using 
End Sub 


Public Function FillXml(fields As Dictionary(Of String, String)) As String 
    ' XML_INFILE => physical path to XML file exported from I-9 
    Dim xmlfile As String 

    xmlfile = Path.Combine(Application.StartupPath, "PDFs\2017-I9_data.xml") 
    xmlfile = Replace(xmlfile, "bin\Debug\", "") 
    Dim kvp As KeyValuePair(Of String, String) 

    Dim xDoc As XDocument = XDocument.Load(xmlfile) 
    For Each kvp In fields 
     ' handle multiple elements in I-9 form 
     Dim elements = xDoc.XPathSelectElements(String.Format("//{0}", kvp.Key)) 
     If elements.Count() > 0 Then 
      For Each e As XElement In elements 
       On Error Resume Next 
       e.Value = kvp.Value 
      Next 
     End If 
    Next 

    Return xDoc.ToString() 
End Function