Как использовать 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