Как использовать itext для заполнения (динамического XFA) PDF из данных в текстовом файле

У меня есть локальная форма PDF, в которой есть определенный шаблон, который никогда не меняется. Я идентифицировал форму как динамическую форму XFA (xml), поскольку набор ключей не возвращался. Я пытаюсь использовать itext, чтобы заполнить форму с данными, содержащимися в файле.txt. Насколько я понимаю, мне нужно каким-то образом получить данные из текстового файла и правильно разместить их в XML-файле, чтобы itext мог манипулировать исходным PDF-файлом, используя заданный XML-файл.

Форма имеет следующий макет в качестве примера:

пример

Пример кода, который я использую в Eclipse, компилируется / выполняется успешно, но для этого требуются данные в файле data.xml чтобы заполнить пустую форму данными поля и вывести заполненную версию. Дело в том, что для моего реального проекта у меня нет файла data.xml, чтобы использовать его для правильного заполнения формы. Необработанные данные поля находятся в файле.txt, где каждая строка содержит данные для другого поля в PDF.

ПРИМЕР: Ссылаясь на изображение выше, мой файл.txt выглядит так для полей до и включая поле, помеченное "ЧЕТЫРЕ":

  • Джон
  • 15
  • черный
  • Honda
  • Тойота
  • брод
  • БМВ

Я запутался в двух вещах:

1. Как извлечь структуру XML оригинального PDF-файла, чтобы я знал формат, которому необходимо следовать при заполнении его данными из файла.txt?

2. Как мне получить значения из текстового файла и правильно вставить их в структуру.xml?

Следующий код работает, но требует data.xml для того, чтобы заполнить "incomplete.pdf". Он использует код xfa.fillXfaForm(new FileInputStream(XML)); для ввода данных, но я застрял на том, как определить структуру для "XML" и как ее заполнить в первую очередь.

Любая помощь приветствуется, большое спасибо.

Код:

package sandbox;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;


import java.io.PrintStream;
import java.util.Set;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.TransformerFactoryConfigurationError;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import com.itextpdf.text.DocumentException;
import com.itextpdf.text.pdf.AcroFields;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfStamper;
import com.itextpdf.text.pdf.XfaForm;


public class FillXFA {

    public static final String SRC = "C:/Workspace/PDF/incomplete.pdf";
    public static final String XML = "C:/Workspace/PDF/data.xml";
    public static final String DEST = "C:/Workspace/PDF/completed.pdf";

    public static void main(String[] args) throws IOException, DocumentException {
        File file = new File(DEST);
        file.getParentFile().mkdirs();
        new FillXFA().manipulatePdf(SRC, DEST);
    }

    public void readXfa(String src, String dest)
            throws IOException, ParserConfigurationException, SAXException,
                TransformerFactoryConfigurationError, TransformerException {
            FileOutputStream os = new FileOutputStream(dest);
            PdfReader reader = new PdfReader(src);
            XfaForm xfa = new XfaForm(reader);
            Document doc = xfa.getDomDocument();
            Transformer tf = TransformerFactory.newInstance().newTransformer();
            tf.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
            tf.setOutputProperty(OutputKeys.INDENT, "yes");
            tf.transform(new DOMSource(doc), new StreamResult(os));
            reader.close();
        }

    public void manipulatePdf(String src, String dest)
        throws IOException, DocumentException {
        PdfReader reader = new PdfReader(src);
        PdfStamper stamper = new PdfStamper(reader,
                new FileOutputStream(dest));
        AcroFields form = stamper.getAcroFields();
        XfaForm xfa = form.getXfa();
        xfa.fillXfaForm(new FileInputStream(XML));
        stamper.close();
        reader.close();
    }
}

1 ответ

В XFA связь между полями формы и данными формы осуществляется с использованием концепции, называемой привязкой данных. Поля могут иметь XPath-подобное выражение для выбора их значения в структуре данных XML. Это подразумевает, что данные XML должны быть соответствующим образом структурированы для работы с определенной формой XFA, но эта структура не обязательно уникальна.

Простой пример: предположим, у вас есть форма XFA с одним текстовым полем. Это текстовое поле имеет привязку данных к любому элементу XML с именем тега "Имя". В этом случае ваш data.xml может быть просто:

<Name>Hurmle</Name>

Но это и бесконечное число различных XML-структур также будут работать:

<Stackru>
    <accounts>
        <account>
            <Name>Hurmle</Name>
        </account>
    </accounts>
</Stackru>

readXfa Метод в вашем примере кода будет работать для извлечения полного потока XML из формы XFA. Он состоит из разных частей. Наиболее актуальными являются:

  • шаблон: описывает структуру логической формы, включая все поля и их привязку данных.
  • xfa: наборы данных: содержит информацию о данных. Состоит из 2 частей.
    • dataDescription: схема для данных формы, необязательно. Грамматика описания данных определена в спецификации XFA.
    • xfa:data: данные формы.

Один из способов определить, какая XML-структура будет работать, - посмотреть на привязку данных всех полей (см. Шаблон). Таким образом, вы будете знать, где поля ожидают получить свои данные. Для нетривиальной формы это может быть сложным и / или много работы.

Если доступно в форме XFA, вы можете использовать dataDescription. Это даст вам структуру для данных и информации, таких как минимальное и максимальное вхождение для элементов.

Наконец, вы можете посмотреть на данные, которые уже в форме (см. Xfa: data). Имейте в виду, что эта структура XML не обязательно завершена: пустые элементы могут быть опущены. Например, если форма имеет 2 поля, значения могут быть указаны как:

<SomeRoot>
    <Field1>Value1</Field1>
    <Field2></Field2>
</SomeRoot>

Но также:

<SomeRoot>
    <Field1>Value1</Field1>
</SomeRoot>

В первом случае вам будет легче определить необходимую структуру. Если xfa:data отсутствует или не заполнена, вы можете попробовать заполнить все поля формы вручную с помощью программы просмотра PDF с поддержкой XFA. При сохранении программа просмотра заполняет данные xfa:data в соответствии с описанием данных и привязкой данных.

Для справки: спецификация XFA

Другие вопросы по тегам