Извлечение содержимого между узлами документа
При работе с документами важно иметь возможность легко извлекать содержимое из определенного диапазона в документе. Однако содержимое может состоять из сложных элементов, таких как абзацы, таблицы, изображения и т.д.
Независимо от того, какой контент необходимо извлечь, метод извлечения этого контента всегда будет определяться тем, какие узлы выбраны для извлечения содержимого между ними. Это могут быть целые текстовые фрагменты или простые текстовые фрагменты.
Существует множество возможных ситуаций и, следовательно, множество различных типов узлов, которые следует учитывать при извлечении содержимого. Например, вы можете захотеть извлечь содержимое между:
- Два конкретных пункта
- Конкретные фрагменты текста
- Поля различных типов, такие как поля слияния
- Начальный и конечный диапазоны закладки или комментария
- Различные тексты, содержащиеся в отдельных разделах
В некоторых ситуациях вам может даже потребоваться объединить различные типы узлов, например, для извлечения содержимого из абзаца и поля или из запуска и закладки.
В этой статье приводится реализация кода для извлечения текста между различными узлами, а также примеры распространенных сценариев.
Зачем извлекать контент
Часто целью извлечения содержимого является дублирование или сохранение его отдельно в новом документе. Например, вы можете извлечь содержимое и:
- Скопируйте его в отдельный документ
- Преобразуйте определенную часть документа в PDF или изображение
- Повторяйте содержимое документа много раз
- Работайте с извлеченным содержимым отдельно от остальной части документа
Этого можно легко достичь, используя Aspose.Words и приведенную ниже реализацию кода.
Алгоритм извлечения контента
Приведенный в этом разделе код рассматривает все возможные ситуации, описанные выше, с помощью одного обобщенного метода, который можно использовать повторно. В общих чертах этот метод включает:
- Сбор узлов, которые определяют область содержимого, которая будет извлечена из вашего документа. Поиск этих узлов осуществляется пользователем в его коде в зависимости от того, что он хочет извлечь.
- Передаем эти узлы методу ExtractContent, представленному ниже. Вы также должны передать логический параметр, который указывает, должны ли эти узлы, действующие как маркеры, быть включены в извлечение или нет.
- Получение списка клонированного содержимого (скопированных узлов), указанного для извлечения. Вы можете использовать этот список узлов любым применимым способом, например, создать новый документ, содержащий только выбранное содержимое.
Как извлечь контент
Чтобы извлечь содержимое из вашего документа, вам необходимо вызвать метод extract_content, описанный ниже, и передать соответствующие параметры. В основе этого метода лежит поиск узлов на уровне блоков (абзацев и таблиц) и их клонирование для создания идентичных копий. Если переданные узлы-маркеры находятся на уровне блока, то метод может просто скопировать содержимое на этом уровне и добавить его в массив.
Однако, если узлы-маркеры являются встроенными (дочерними по отношению к абзацу), ситуация становится более сложной, поскольку необходимо разделить абзац на встроенном узле, будь то прогон, поля закладок и т.д. Содержимое в клонированных родительских узлах, отсутствующее между маркерами, удаляется. Этот процесс используется для обеспечения того, чтобы встроенные узлы сохраняли форматирование родительского абзаца. Метод также выполняет проверку узлов, переданных в качестве параметров, и генерирует исключение, если какой-либо из узлов является недопустимым. В этот метод передаются следующие параметры:
- startNode и endNode. Первые два параметра - это узлы, которые определяют, где должно начинаться и заканчиваться извлечение содержимого соответственно. Эти узлы могут быть как на уровне блоков (Paragraph, Table, так и на встроенном уровне (например, Run, FieldStart, BookmarkStart и т.д.):
- Чтобы передать поле, вы должны передать соответствующий объект FieldStart.
- Чтобы передать закладки, необходимо передать узлы BookmarkStart и BookmarkEnd.
- Для передачи комментариев следует использовать узлы CommentRangeStart и CommentRangeEnd.
- isInclusive. Определяет, будут ли маркеры включены в извлечение или нет. Если для этого параметра установлено значение false и передается один и тот же узел или последовательные узлы, то будет возвращен пустой список:
- Если передается узел FieldStart, то этот параметр определяет, следует ли включать или исключать все поле целиком.
- Если передан узел BookmarkStart или BookmarkEnd, этот параметр определяет, включена ли закладка или только содержимое между диапазонами закладок.
- Если передан узел CommentRangeStart или CommentRangeEnd, этот параметр определяет, должен ли быть включен сам комментарий или только содержимое в диапазоне комментариев.
Реализацию метода extract_content вы можете найти здесь. Этот метод будет описан в сценариях, описанных в этой статье.
Мы также определим пользовательский метод, позволяющий легко создавать документ из извлеченных узлов. Этот метод используется во многих сценариях, описанных ниже, и просто создает новый документ и импортирует в него извлеченное содержимое.
В следующем примере кода показано, как взять список узлов и вставить их в новый документ:
Извлекайте содержимое между абзацами
Это демонстрирует, как использовать описанный выше метод для извлечения содержимого между конкретными абзацами. В данном случае мы хотим извлечь текст письма, найденного в первой половине документа. Мы можем сказать, что оно находится между 7-м и 11-м абзацами.
Приведенный ниже код выполняет эту задачу. Соответствующие абзацы извлекаются с использованием метода CompositeNode.get_child в документе и с передачей указанных индексов. Затем мы передаем эти узлы методу extract_content и указываем, что они должны быть включены в извлечение. Этот метод вернет скопированное содержимое между этими узлами, которое затем будет вставлено в новый документ.
В следующем примере кода показано, как извлечь содержимое между определенными абзацами, используя метод extract_content, описанный выше:
Извлекать содержимое между различными типами узлов
Мы можем извлекать содержимое из любых комбинаций блоков или встроенных узлов. В приведенном ниже сценарии мы будем извлекать содержимое между первым абзацем и таблицей во втором разделе включительно. Мы получаем узлы-маркеры, вызывая методы Body.first_paragraph и CompositeNode.get_child во втором разделе документа, чтобы получить соответствующие узлы Paragraph и Table. Для небольшого изменения давайте вместо этого продублируем содержимое и вставим его под оригинал.
В следующем примере кода показано, как извлечь содержимое из абзаца и таблицы с помощью метода extract_content:
Извлекайте содержимое из абзацев в зависимости от стиля
Возможно, вам потребуется извлечь содержимое между абзацами одного и того же или разного стиля, например, между абзацами, помеченными стилями заголовков.
Приведенный ниже код показывает, как этого добиться. Это простой пример, который позволяет извлекать содержимое между первым экземпляром стилей “Heading 1” и “Заголовок 3” без извлечения заголовков. Для этого мы устанавливаем последнему параметру значение false, которое указывает, что узлы-маркеры не должны быть включены.
В правильной реализации это должно выполняться в цикле для извлечения содержимого между всеми абзацами этих стилей из документа. Извлеченное содержимое копируется в новый документ.
В следующем примере кода показано, как извлекать содержимое между абзацами с определенными стилями, используя метод extract_content:
Извлекайте содержимое Между Определенными Запусками
Вы также можете извлекать содержимое между встроенными узлами, такими как Run. Фрагменты из разных абзацев могут быть переданы в качестве маркеров. В приведенном ниже коде показано, как извлекать определенный текст из одного и того же узла Paragraph.
В следующем примере кода показано, как извлекать содержимое между конкретными запусками одного и того же абзаца, используя метод extract_content:
Извлекать содержимое с помощью поля
Чтобы использовать поле в качестве маркера, необходимо передать узел FieldStart. Последний параметр метода extract_content определяет, следует ли включать все поле целиком или нет. Давайте выделим содержимое между полем слияния “FullName” и абзацем в документе. Мы используем метод DocumentBuilder.move_to_merge_field класса DocumentBuilder. Это вернет узел FieldStart из переданного ему поля name of merge.
В нашем случае давайте установим для последнего параметра, переданного методу extract_content, значение False
, чтобы исключить поле из извлечения. Мы преобразуем извлеченный контент в PDF.
В следующем примере кода показано, как извлечь содержимое из определенного поля и абзаца в документе с помощью метода extract_content:
Извлечение содержимого из закладки
В документе содержимое, определенное в закладке, инкапсулируется узлами BookmarkStart и BookmarkEnd. Содержимое, находящееся между этими двумя узлами, и составляет закладку. Вы можете использовать любой из этих узлов в качестве любого маркера, даже из разных закладок, при условии, что начальный маркер отображается перед конечным маркером в документе. Мы извлекем это содержимое в новый документ, используя приведенный ниже код. Параметр isInclusive показывает, как сохранить или удалить закладку.
В следующем примере кода показано, как извлечь содержимое, на которое ссылается закладка, используя метод extract_content:
Извлекать содержимое из комментария
Комментарий состоит из узлов CommentRangeStart, CommentRangeEnd и Comment. Все эти узлы являются встроенными. Первые два узла содержат содержимое документа, на который ссылается комментарий, как показано на скриншоте ниже. Узел Comment сам по себе является узлом InlineStory, который может содержать абзацы и заголовки. Он представляет собой сообщение комментария, отображаемое в виде пузырька комментариев на панели просмотра. Поскольку этот узел является встроенным и является потомком тела, вы также можете извлечь содержимое из этого сообщения.
Комментарий содержит заголовок, первый абзац и таблицу во втором разделе. Давайте перенесем этот комментарий в новый документ. Параметр isInclusive определяет, следует ли сохранить сам комментарий или удалить его.
В следующем примере кода показано, как это сделать:
Как извлечь только текст
Существуют следующие способы извлечения текста из документа:
- Используйте Document.save для сохранения в виде обычного текста в файл или поток
- Используйте Node.to_string и передайте параметр SaveFormat.TEXT. Внутренне это вызывает функцию сохранения в виде текста в потоке памяти и возвращает результирующую строку
- Используйте Node.get_text для извлечения текста, содержащего все управляющие символы Microsoft Word, включая коды полей
Используя Node.get_text и Node.to_string
Документ Word может содержать управляющие символы, которые обозначают специальные элементы, такие как поле, конец ячейки, конец раздела и т.д. Полный список возможных управляющих символов Word определен в классе ControlChar. Метод Node.get_text возвращает текст со всеми управляющими символами, присутствующими в узле.
Вызов to_string возвращает только текстовое представление документа без управляющих символов. Дополнительную информацию об экспорте в виде обычного текста смотрите в разделе Использование SaveFormat.TEXT.
В следующем примере кода показана разница между вызовом методов get_text и to_string на узле:
Используя SaveFormat.Text
В этом примере документ сохраняется следующим образом:
- Отфильтровывает символы полей и коды полей, форму, сноски, концевые примечания и ссылки на комментарии
- Заменяет символы конца абзаца ControlChar.Cr комбинациями ControlChar.CrLf
- Использует кодировку UTF8
В следующем примере кода показано, как сохранить документ в формате TXT:
Извлечение изображений из фигур
Для выполнения некоторых задач вам может потребоваться извлечь изображения из документов. Aspose.Words это также позволяет это сделать.
В следующем примере кода показано, как извлекать изображения из документа: