
Когда кто-то заполняет PDF-форму и сохраняет её, введённые значения хранятся внутри структур полей документа, а не в виде обычного текста, который можно искать или массово копировать. Для формы с тридцатью или сорока полями ручной перенос данных становится узким местом. Более глубокая проблема в том, что каждый тип поля хранит своё значение по-разному: текстовое поле предоставляет строку, флажок сообщает логическое значение, раскрывающийся список отделяет варианты от выбора, а переключатель хранит выбранный элемент. Единого универсального вызова "дай мне значение" не существует.
В этой статье рассматривается извлечение значений полей формы из PDF с помощью Spire.PDF for JavaScript. Библиотека работает на WebAssembly в браузере, поэтому документ обрабатывается локально через виртуальную файловую систему без обращения к серверу. Вы увидите, как перебрать коллекцию полей, выполнить ветвление по типу каждого поля и прочитать нужное свойство для текстовых полей, списков, раскрывающихся списков, переключателей и флажков.
По вопросам настройки и конфигурации проекта обращайтесь к разделу Интеграция Spire.PDF for JavaScript в проект React. Приведённый ниже код предполагает, что Spire.PDF установлен, а модуль WASM инициализирован.
Типы полей вкратце
Прежде чем перейти к реализации, полезно разобраться, как каждый тип поля предоставляет своё значение. Spire.PDF for JavaScript представляет поля формы в виде классов виджетов, и свойство, хранящее текущее значение, отличается от типа к типу:
| Тип поля | Класс виджета | Свойство для чтения | Примечания |
|---|---|---|---|
| Текстовое поле | PdfTextBoxFieldWidget |
Text |
Напрямую возвращает введённую строку. |
| Поле списка | PdfListBoxWidgetFieldWidget |
SelectedValue |
Values — это полный список вариантов, а не выбор пользователя. |
| Раскрывающийся список | PdfComboBoxWidgetFieldWidget |
SelectedValue |
Та же модель с двумя свойствами, что и у поля списка. |
| Переключатель | PdfRadioButtonListFieldWidget |
Value |
За один шаг возвращает строку выбранного элемента. |
| Флажок | PdfCheckBoxWidgetFieldWidget |
Checked |
Логическое состояние. Value не определено — не используйте его. |
Закономерность очевидна: единого универсального свойства нет. Логика извлечения должна проверять тип каждого поля и читать соответствующее свойство — именно это и реализуется в следующем разделе.
Перебор полей и чтение по типу
Основной процесс состоит из трёх шагов: загрузить PDF, получить его форму в виде PdfFormWidget, затем перебрать коллекцию FieldsWidget и выполнить ветвление по классу каждого поля с помощью instanceof. В каждой ветке читается свойство, специфичное для типа, а результат добавляется к строке отчёта. Поскольку ветвление охватывает все поддерживаемые типы, вам не нужно заранее знать, какие поля содержит документ: нераспознанные поля просто попадают в ветку с меткой по умолчанию.
function App() {
const getAllFieldValues = async () => {
// Get the Spire.PDF WASM module
const pdfModule = window.wasmModule?.spirepdf;
// Check that the module is ready
if (!pdfModule) {
alert('Spire.PDF is not ready yet');
return;
}
// Load the PDF file to be read into the VFS
const inputFileName = 'ApplicationForm.pdf';
await window.spire.FetchFileToVFS(inputFileName, "", `${process.env.PUBLIC_URL}/data/`);
// Create a PdfDocument object and load the PDF document
const doc = new pdfModule.PdfDocument();
doc.LoadFromFile(inputFileName);
// Build a PdfFormWidget from the document's form handle; FieldsWidget is its field collection
const formWidget = new pdfModule.PdfFormWidget(doc.Form.H);
const fields = formWidget.FieldsWidget;
let report = '';
// Walk the field collection, check each type, and read the matching value
for (let i = 0; i < fields.Count; i++) {
const field = fields.get_Item({ index: i });
// Both the type name and the value are filled in by the type dispatch
let type = 'Unknown';
let value = '(Unrecognized field type)';
if (field instanceof pdfModule.PdfTextBoxFieldWidget) {
// Text box field: read Text directly
type = 'TextBox';
value = field.Text;
} else if (field instanceof pdfModule.PdfListBoxWidgetFieldWidget) {
// List box field: Values holds every option, SelectedValue is the current one
const options = [];
for (let j = 0; j < field.Values.Count; j++) {
options.push(field.Values.get_Item(j).Value);
}
type = 'ListBox';
value = `Selected ${field.SelectedValue}, options ${options.join(', ')}`;
} else if (field instanceof pdfModule.PdfComboBoxWidgetFieldWidget) {
// Combo box field: like a list box, it has an option collection and a selected value
const options = [];
for (let j = 0; j < field.Values.Count; j++) {
options.push(field.Values.get_Item(j).Value);
}
type = 'ComboBox';
value = `Selected ${field.SelectedValue}, options ${options.join(', ')}`;
} else if (field instanceof pdfModule.PdfRadioButtonListFieldWidget) {
// Radio button field: Value is the selected item
type = 'RadioButton';
value = `Selected ${field.Value}`;
} else if (field instanceof pdfModule.PdfCheckBoxWidgetFieldWidget) {
// Check box field: Checked gives the state, not Value
type = 'CheckBox';
value = field.Checked ? 'Checked' : 'Not checked';
}
report += `Field "${field.Name}" (${type}): ${value}\n`;
}
const outputFileName = 'AllFieldValues.txt';
window.dotnetRuntime.Module.FS.writeFile(outputFileName, report);
doc.Close();
// Read the generated file from the VFS and trigger the download
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: 'text/plain' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = outputFileName;
a.click();
URL.revokeObjectURL(url);
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>Extract Form Field Values</h1>
<button onClick={getAllFieldValues}>
Extract values
</button>
</div>
);
}
export default App;
После завершения цикла строка отчёта содержит по одной строке на каждое поле с его именем, типом и текущим значением. Файл записывается в виртуальную файловую систему, а затем скачивается как текстовый файл:

Цепочка instanceof — сердце этого подхода. Каждая ветка точно знает, какое свойство читать, поэтому результат будет правильным независимо от того, сколько типов полей смешано в документе. В следующих трёх разделах рассматриваются подводные камни, возникающие, когда свойство значения поля оказывается не тем, которое вы ожидали.
Флажки: Checked или Value
Частая ошибка при чтении полей-флажков — обращение к свойству Value. Виджет флажка — PdfCheckBoxWidgetFieldWidget — вообще не предоставляет Value; попытка его прочитать возвращает undefined. Внутри флажок отслеживает своё состояние через экспортные значения: Off, когда флажок не установлен, и Yes или пользовательскую экспортную строку, когда он установлен. Обычная строка не может надёжно сообщить, выбран ли флажок, поэтому в API намеренно опущено Value и вместо него предложено Checked.
Решение простое — всегда используйте логическое свойство Checked:
// Check the state with Checked, not Value
const checked = field.Checked;
Оно возвращает true, когда флажок установлен, и false в противном случае, предоставляя чистое логическое значение для дальнейшей логики без какого-либо разбора строк.
Списки и раскрывающиеся списки: SelectedValue или Values
Поля списков и раскрывающиеся списки используют модель данных из двух частей, которая сбивает с толку многих разработчиков. И PdfListBoxWidgetFieldWidget, и PdfComboBoxWidgetFieldWidget предоставляют коллекцию Values и строку SelectedValue, и легко предположить, что Values содержит введённое пользователем значение. Это не так.
Values — это полный набор доступных вариантов. Каждый элемент коллекции — объект PdfListWidgetItem, поэтому, чтобы получить текст варианта, его нужно развернуть с помощью .Value. Перебор Values показывает, что пользователь мог выбрать, а не то, что он выбрал на самом деле. Реальный выбор пользователя хранится в SelectedValue в виде обычной строки.
Используйте SelectedValue для текущего значения и перебирайте Values только тогда, когда нужно перечислить доступные варианты:
// The text of the currently selected item
const selected = field.SelectedValue;
// Every available option
const options = [];
for (let j = 0; j < field.Values.Count; j++) {
options.push(field.Values.get_Item(j).Value);
}
Важно не путать эти два свойства: если считать Values ответом, вы получите список вариантов вместо заполненного результата, а их длины совпадают редко.
Работа с зашифрованными PDF-файлами
Извлечение данных формы начинается с открытия документа. Если PDF защищён паролем, вызов LoadFromFile только с именем файла вызывает ошибку — "Can not open an encrypted document. The password is invalid." — и объект документа не возвращается. До полей формы дело так и не доходит.
Решение — передать пароль для открытия вторым аргументом:
doc.LoadFromFile(inputFileName, 'spire123');
После успешного открытия документа остальной процесс извлечения — создание PdfFormWidget, перебор полей, ветвление по типу — работает точно так же, как и с незашифрованным файлом. Пароль только ограничивает начальную загрузку; он не влияет на то, как читаются значения полей.
См. также
- Интеграция Spire.PDF for JavaScript в проект React — настройка, установка и инициализация WASM
- Заполнение полей PDF-формы с помощью Spire.PDF for JavaScript — программная запись значений в поля формы
- Импорт и экспорт данных PDF-формы с помощью Spire.PDF for JavaScript — сериализация данных формы в файлы FDF/XFDF
Если вы хотите удалить оценочное сообщение из итогового документа или избавиться от ограничений функциональности, свяжитесь с отделом продаж, чтобы получить временную лицензию сроком на 30 дней.