Когда вы сравниваете два файла Word, и единственное различие заключается в нумерации списка, например пункты, которые были 1. и 2. теперь стали a. и b., или нумерованный список превратился в маркированный, Aspose.Words по умолчанию не сообщает о различиях. Этот учебник показывает, как обнаружить изменения нумерации при сравнении файлов Word в Python. Он также объясняет, как просматривать, принимать или отклонять найденные изменения.
Ключевые выводы
- По умолчанию изменение стиля нумерации списка или символа маркера не приводит к появлению ревизий при сравнении файлов Word.
- Установка
options.advanced_options.compare_list_definitions = Trueсообщает о каждом затронутом абзаце списка как о ревизииFORMAT_CHANGE. - Изменения текста внутри элементов списка фиксируются в любом случае. Эта опция лишь добавляет изменения нумерации и маркеров поверх.
ignore_formatting=Trueскрывает изменения нумерации, даже если опция включена.
Почему изменения нумерации не отображаются по умолчанию
Нумерация и маркеры в Word берутся из определения списка. Оно описывает, как выглядит каждый уровень списка: стиль номера (1., a., i.), символ маркера и связанное форматирование. При сравнении документов Aspose.Words по умолчанию следует поведению Microsoft Word и исключает определения списков из сравнения. Поэтому, если изменилась только нумерация, сравнение ничего не сообщает.
Опция compare_list_definitions не имеет эквивалента в Word. Она указывает Aspose.Words включать определения списков в сравнение. Вот что мы увидели при сравнении списков из двух элементов в версии 26.9:
| Исходный список | Отредактированный список | Опция выключена | Опция включена |
|---|---|---|---|
Нумерованный 1. 2. | Маркированный | 0 изменений | 2 FORMAT_CHANGE |
Нумерованный 1. 2. | Буквенный a. b. | 0 изменений | 2 FORMAT_CHANGE |
| Нумерованный, “Элемент 2” | Маркированный, “Элемент два” | 2 (DELETION, INSERTION) | 4 (добавляет 2 FORMAT_CHANGE) |
| Нумерованный | Идентичный нумерованный список | 0 изменений | 0 изменений |
Последняя строка имеет значение на практике. Включение этой опции не создает дополнительных ревизий для списков, которые одинаковы в обоих файлах.
Требования
Вам требуется Aspose.Words for Python via .NET 26.9 или более поздняя версия. Установите или обновите его из PyPI:
pip install --upgrade "aspose-words>=26.9"
Без лицензии Aspose.Words работает в режиме оценки с ограничениями. Временная лицензия, полученная через временную лицензию, устраняет их, пока вы тестируете.
Посмотрите разницу: изменения нумерации с опцией и без неё
Следующий скрипт создает два документа, содержащих одинаковые два элемента. Первый использует нумерованный список, а второй — маркированный список. Он сравнивает их дважды: один раз с отключённой опцией и один раз с включённой, чтобы вы могли точно увидеть, какие изменения вносит опция.
import datetime
import aspose.words as aw
def build_list_document(bulleted: bool) -> aw.Document:
"""Create a two-item list, either numbered or bulleted."""
doc = aw.Document()
builder = aw.DocumentBuilder(doc=doc)
if bulleted:
builder.list_format.apply_bullet_default()
else:
builder.list_format.apply_number_default()
builder.writeln("Item 1")
builder.writeln("Item 2")
builder.list_format.remove_numbers()
return doc
def compare_lists(compare_list_definitions: bool) -> aw.Document:
original = build_list_document(bulleted=False)
edited = build_list_document(bulleted=True)
options = aw.comparing.CompareOptions()
options.advanced_options.compare_list_definitions = compare_list_definitions
# compare() writes revisions into `original`; it returns nothing.
original.compare(
document=edited,
author="Reviewer",
date_time=datetime.datetime.now(),
options=options,
)
return original
for flag in (False, True):
result = compare_lists(flag)
print(f"compare_list_definitions={flag}: {result.revisions.count} revision(s)")
for revision in result.revisions:
revision_type = aw.RevisionType(revision.revision_type).name
text = revision.parent_node.get_text().strip()
print(f" {revision_type}: {text}")
result.save("compared-lists.docx")
Запуск скрипта выводит:
compare_list_definitions=False: 0 revision(s)
compare_list_definitions=True: 2 revision(s)
FORMAT_CHANGE: Item 1
FORMAT_CHANGE: Item 2
Как работает код
build_list_documentиспользуетDocumentBuilder.list_formatдля начала нумерованного или маркированного списка по умолчанию, записывает два элемента и затем вызываетremove_numbers(), чтобы последующие абзацы не были частью списка.CompareOptions.advanced_optionsраскрываетcompare_list_definitions, который по умолчанию имеет значениеFalse.original.compare(...)сравниваетoriginalсeditedи фиксирует различия как правки внутриoriginal. Метод возвращаетNone, поэтому результаты следует всегда читать из документа, на котором он был вызван.parent_nodeкаждой правки — это абзац списка, форматирование которого изменилось.revision_typeравноRevisionType.FORMAT_CHANGEдля изменений нумерации и маркеров.
Обнаружение изменений нумерации между двумя файлами Word
В реальном рабочем процессе вы сравниваете два существующих файла, например две версии контракта. Такие сравнения обычно также содержат другие правки, поэтому скрипт ниже оставляет только изменения форматирования, которые находятся в абзацах списков.
import datetime
import aspose.words as aw
original = aw.Document("contract-v1.docx")
edited = aw.Document("contract-v2.docx")
options = aw.comparing.CompareOptions()
options.advanced_options.compare_list_definitions = True
original.compare(edited, "Reviewer", datetime.datetime.now(), options)
# Keep only formatting revisions that sit on list paragraphs.
list_changes = [
rev for rev in original.revisions
if rev.revision_type == aw.RevisionType.FORMAT_CHANGE
and rev.parent_node is not None
and rev.parent_node.node_type == aw.NodeType.PARAGRAPH
and rev.parent_node.as_paragraph().list_format.is_list_item
]
print(f"Total revisions: {original.revisions.count}")
print(f"Formatting changes on list paragraphs: {len(list_changes)}")
for rev in list_changes:
print(f" {rev.parent_node.get_text().strip()}")
original.save("contract-compared.docx")
В нашем тесте версия 2 контракта изменила нумерованный список на маркеры и также сделала отдельное предложение полужирным. Вывод был:
Total revisions: 5
Formatting changes on list paragraphs: 2
Invoices are due in 30 days.
Late fees apply after 45 days.
Фильтр выбирает два пункта списка и пропускает изменение полужирного шрифта, потому что эта правка относится к тексту, а не к абзацу списка. Имейте в виду, что он сопоставляет любые изменения форматирования уровня абзаца в пункте списка, такие как изменённый отступ, а не только нумерацию. Проверьте сохранённый документ, если вам нужно различать их.
Обзор, принятие или отклонение изменений нумерации
Поскольку изменения нумерации являются обычными изменениями формата, вы обрабатываете их так же, как любые другие изменения:
revisions.accept_all()применяет отредактированное форматирование списка. В первом примере оба пункта становятся маркерами.revisions.reject_all()сохраняет оригинальное форматирование, поэтому пункты остаются нумерованными1.и2..- Сохранение документа записывает изменения как отслеживаемые правки, поэтому рецензенты могут открыть файл в Microsoft Word и решить по каждому изменению самостоятельно.
Вы также можете вызвать accept() или reject() для отдельных объектов Revision, например, только для элементов списка list_changes, указанных в предыдущем разделе.
Когда следует обнаруживать изменения нумерации
Включите эту опцию, когда нумерация списка имеет значение для ваших рецензентов. Юридические и нормативные документы — типичный пример: переименование пунктов с 1. на (a) меняет то, как другие документы ссылаются на них, поэтому рецензенту необходимо видеть это. Это также полезно, когда вы переносите документы между системами и хотите убедиться, что нумерация списка сохранилась без изменений.
Отключайте его, если вам важна только формулировка. Обзоры контента, проверки перевода и диффы на уровне текста легче читать без смешанных с ними правок форматирования.
На что обратить внимание
ignore_formattingпереопределяет параметр. Если вы установитеoptions.ignore_formatting = True, изменения нумерации не будут сообщаться, даже приcompare_list_definitions = True.- Файлы не должны содержать ревизий перед сравнением. Если в любом из документов уже есть отслеживаемые изменения,
compareгенерируетRuntimeError, сообщающий, что сравниваемые документы не должны иметь ревизий. Сначала примите или отклоните существующие ревизии. Это также означает, что вы не можете выполнить второе сравнение документа, в котором уже находятся результаты первого; каждый раз перегружайте файлы. - Другие ревизии всё равно отображаются. Вставленный или удалённый текст в пункте списка фиксируется независимо от того, включён параметр или нет, поэтому проверяйте
revision_type, если нужно отделить изменения нумерации от изменений формулировок.
Следующие шаги
Статья Compare Documents в документации Aspose.Words for Python охватывает остальные настройки сравнения, включая детализацию, цель сравнения и параметры игнорирования.
Часто задаваемые вопросы
Почему Aspose.Words не обнаруживает изменения нумерации при сравнении файлов Word? По умолчанию Aspose.Words следует Microsoft Word и исключает определения списков, такие как стиль нумерации или символ маркера, из сравнения. Список, который меняется с нумерации на маркеры, не приводит к появлению изменений, если не включить
compare_list_definitions.Как обнаружить изменения нумерации в Python? Создайте
CompareOptions, установитеoptions.advanced_options.compare_list_definitionsвTrueи передайте параметры вDocument.compare. Каждый абзац списка, у которого изменилась нумерация или маркер, получает ревизиюFORMAT_CHANGE.Какой тип ревизии создаёт изменение нумерации? Каждый затронутый абзац списка получает ревизию типа
RevisionType.FORMAT_CHANGE. При её принятии применяется форматирование списка из отредактированного файла, а при отклонении сохраняется оригинальное.Работает ли параметр совместно с ignore_formatting? Нет. Когда
CompareOptions.ignore_formattingравноTrue, изменения нумерации не сообщаются, даже еслиcompare_list_definitionsравноTrue.Что возвращает Document.compare? Ничего. Он записывает различия как правки в документ, к которому вы вызываете его, поэтому вы читаете их из коллекции
revisionsэтого документа.В какой версии Aspose.Words for Python была добавлена эта опция? Свойство
compare_list_definitionsклассаAdvancedCompareOptionsбыло добавлено в Aspose.Words for Python via .NET 26.9.
