Категория

Чтение значений полей PDF-форм по типам с помощью JavaScript

2026-09-28 08:33:44 Allen Yang
AI Summarize:
ChatGPT
ChatGPT ✓
Claude ✓
Grok ✓
Perplexity ✓
Quick
Quick
Concise overview
Highlights
Key takeaways
Detailed
Structured explanation
Brief
One sentence summary
Summarize |

Значения, собранные при переборе всех полей формы

Когда кто-то заполняет 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, перебор полей, ветвление по типу — работает точно так же, как и с незашифрованным файлом. Пароль только ограничивает начальную загрузку; он не влияет на то, как читаются значения полей.


См. также


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