Python-docx: удалить раздел библиографии (w:sdt)

Моя конечная цель — найти и удалить любой раздел библиографии из документа Microsoft Word.

Как упоминалось в этом выпуске . В настоящее время нет поддержки API для тегов w:sdt (думаю, только для библиографий). Однако в ответ на эту проблему был предложен обходной путь:

paragraph = ... # however you get the paragraph, maybe with `for paragraph in document.paragraphs`
p = paragraph._element
sdts = p.xpath('w:sdt')
for sdt in sdts:
    parent = sdt.getparent()
    parent.remove(sdt)

При использовании вышеизложенного XML документа обновляется и удаляет теги w:sdt так, как я хочу. Однако когда я сохраняю новый документ, выходной файл .docx по-прежнему включает раздел библиографии.

Почему, несмотря на то, что XML-файл документа Python-docx не включает элементы w:sdt, это не отражается после сохранения и открытия документа в Microsoft Word. Я прочитал здесь, что отношения документов могут иметь какое-то отношение к этому, но, учитывая, что я не получаю ошибок при открытии нового документа Word, я не думаю, что это проблема. Есть идеи?

Вот предварительная обработка фрагмента XML:

<w:p xmlns:w = "http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:w14 = "http://schemas.microsoft.com/office/word/2010/wordml" xmlns:wpc = "http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas" xmlns:cx = "http://schemas.microsoft.com/office/drawing/2014/chartex" xmlns:cx1 = "http://schemas.microsoft.com/office/drawing/2015/9/8/chartex" xmlns:cx2 = "http://schemas.microsoft.com/office/drawing/2015/10/21/chartex" xmlns:cx3 = "http://schemas.microsoft.com/office/drawing/2016/5/9/chartex" xmlns:cx4 = "http://schemas.microsoft.com/office/drawing/2016/5/10/chartex" xmlns:cx5 = "http://schemas.microsoft.com/office/drawing/2016/5/11/chartex" xmlns:cx6 = "http://schemas.microsoft.com/office/drawing/2016/5/12/chartex" xmlns:cx7 = "http://schemas.microsoft.com/office/drawing/2016/5/13/chartex" xmlns:cx8 = "http://schemas.microsoft.com/office/drawing/2016/5/14/chartex" xmlns:mc = "http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:aink = "http://schemas.microsoft.com/office/drawing/2016/ink" xmlns:am3d = "http://schemas.microsoft.com/office/drawing/2017/model3d" xmlns:o = "urn:schemas-microsoft-com:office:office" xmlns:oel = "http://schemas.microsoft.com/office/2019/extlst" xmlns:r = "http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:m = "http://schemas.openxmlformats.org/officeDocument/2006/math" xmlns:v = "urn:schemas-microsoft-com:vml" xmlns:wp14 = "http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing" xmlns:wp = "http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing" xmlns:w10 = "urn:schemas-microsoft-com:office:word" xmlns:w15 = "http://schemas.microsoft.com/office/word/2012/wordml" xmlns:w16cex = "http://schemas.microsoft.com/office/word/2018/wordml/cex" xmlns:w16cid = "http://schemas.microsoft.com/office/word/2016/wordml/cid" xmlns:w16 = "http://schemas.microsoft.com/office/word/2018/wordml" xmlns:w16sdtdh = "http://schemas.microsoft.com/office/word/2020/wordml/sdtdatahash" xmlns:w16se = "http://schemas.microsoft.com/office/word/2015/wordml/symex" xmlns:wpg = "http://schemas.microsoft.com/office/word/2010/wordprocessingGroup" xmlns:wpi = "http://schemas.microsoft.com/office/word/2010/wordprocessingInk" xmlns:wne = "http://schemas.microsoft.com/office/word/2006/wordml" xmlns:wps = "http://schemas.microsoft.com/office/word/2010/wordprocessingShape" w14:paraId = "2BE25C04" w14:textId = "0C685DB1" w:rsidR = "00572630" w:rsidRDefault = "006A14EA">
  <w:r>
    <w:t xml:space = "preserve">Hey there </w:t>
  </w:r>
  <w:sdt>
    <w:sdtPr>
      <w:id w:val = "-39898552"/>
      <w:citation/>
    </w:sdtPr>
    <w:sdtContent>
      <w:r>
        <w:fldChar w:fldCharType = "begin"/>
      </w:r>
      <w:r>
        <w:instrText xml:space = "preserve"> CITATION Fra69 \l 2057 </w:instrText>
      </w:r>
      <w:r>
        <w:fldChar w:fldCharType = "separate"/>
      </w:r>
      <w:r>
        <w:rPr>
          <w:noProof/>
        </w:rPr>
        <w:t>(Herbert, 1969)</w:t>
      </w:r>
      <w:r>
        <w:fldChar w:fldCharType = "end"/>
      </w:r>
    </w:sdtContent>
  </w:sdt>
</w:p>

Вот постобработка фрагмента XML, где вы можете видеть, что библиография была удалена, но эти изменения не видны, когда я сохраняю и открываю документ:

<w:p xmlns:w = "http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:w14 = "http://schemas.microsoft.com/office/word/2010/wordml" xmlns:wpc = "http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas" xmlns:cx = "http://schemas.microsoft.com/office/drawing/2014/chartex" xmlns:cx1 = "http://schemas.microsoft.com/office/drawing/2015/9/8/chartex" xmlns:cx2 = "http://schemas.microsoft.com/office/drawing/2015/10/21/chartex" xmlns:cx3 = "http://schemas.microsoft.com/office/drawing/2016/5/9/chartex" xmlns:cx4 = "http://schemas.microsoft.com/office/drawing/2016/5/10/chartex" xmlns:cx5 = "http://schemas.microsoft.com/office/drawing/2016/5/11/chartex" xmlns:cx6 = "http://schemas.microsoft.com/office/drawing/2016/5/12/chartex" xmlns:cx7 = "http://schemas.microsoft.com/office/drawing/2016/5/13/chartex" xmlns:cx8 = "http://schemas.microsoft.com/office/drawing/2016/5/14/chartex" xmlns:mc = "http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:aink = "http://schemas.microsoft.com/office/drawing/2016/ink" xmlns:am3d = "http://schemas.microsoft.com/office/drawing/2017/model3d" xmlns:o = "urn:schemas-microsoft-com:office:office" xmlns:oel = "http://schemas.microsoft.com/office/2019/extlst" xmlns:r = "http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:m = "http://schemas.openxmlformats.org/officeDocument/2006/math" xmlns:v = "urn:schemas-microsoft-com:vml" xmlns:wp14 = "http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing" xmlns:wp = "http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing" xmlns:w10 = "urn:schemas-microsoft-com:office:word" xmlns:w15 = "http://schemas.microsoft.com/office/word/2012/wordml" xmlns:w16cex = "http://schemas.microsoft.com/office/word/2018/wordml/cex" xmlns:w16cid = "http://schemas.microsoft.com/office/word/2016/wordml/cid" xmlns:w16 = "http://schemas.microsoft.com/office/word/2018/wordml" xmlns:w16sdtdh = "http://schemas.microsoft.com/office/word/2020/wordml/sdtdatahash" xmlns:w16se = "http://schemas.microsoft.com/office/word/2015/wordml/symex" xmlns:wpg = "http://schemas.microsoft.com/office/word/2010/wordprocessingGroup" xmlns:wpi = "http://schemas.microsoft.com/office/word/2010/wordprocessingInk" xmlns:wne = "http://schemas.microsoft.com/office/word/2006/wordml" xmlns:wps = "http://schemas.microsoft.com/office/word/2010/wordprocessingShape" w14:paraId = "2BE25C04" w14:textId = "0C685DB1" w:rsidR = "00572630" w:rsidRDefault = "006A14EA">
  <w:r>
    <w:t xml:space = "preserve">Hey there </w:t>
  </w:r>
</w:p>

Примечание. Я задаю этот вопрос здесь, поскольку python-docx GitHub в последнее время не проявляет особой активности.

некоторые примечания, которые могут вам помочь (я не знаю, как использовать библиотеку python-docx, чтобы определить, что нужно удалить, но вы можете это сделать). 1. Элементы w:set можно использовать для нескольких целей: не только для библиографии, но и для цитирования и различных типов управления контентом. 2. Элементы w:sdt не обязательно содержатся в элементах Paragraph. Фактически, если вы добавите библиографию в пустой абзац в Word, тег set не будет содержаться в теге w:p. Я не знаю, возможно ли это когда-нибудь.

jonsson 26.03.2024 18:51

3. Библиография обычно состоит из двух элементов множества, один из которых вложен в другой. Внутренний должен содержать элемент <w:bibliography>. (Не уверен, что вы увидите, если вставите старомодное поле {BIBLIOGRAPHY} вручную — я не проверял.). Но пока библиография всегда строится таким образом, если вы можете понять, как найти элементы/теги w:bibliography, а затем найти включающий тег set и заключающий его тег set, вы сможете заставить это работать.

jonsson 26.03.2024 18:55

4. Теги sdt описаны в стандартном документе ISO 29500, часть 1 (Справочник по основам и языку разметки) в разделе 17.5.2. У Microsoft есть собственные документы по стандартам, в которых документируются отклонения от стандартов ISO. 5. В вашем документе будет часть «Библиография», которая будет описана в разделе «Связь». Когда вы удаляете фактическую библиографию, вам также не нужно удалять часть «Библиография».

jonsson 26.03.2024 19:01

Спасибо за ответ, просматривая мой тестовый XML-файл документа, я вижу, что теги sdt не являются дочерними элементами какого-либо тега p, но, несмотря на это, включенный исходный код извлекает теги sdt. Кроме того, мой тестовый документ не содержит тега w:bibilography — тот, о котором идет речь, был создан с использованием функций библиографии Word по умолчанию.

Charlie Clarke 27.03.2024 11:44

Это интересно: в моем тесте также использовалась библиография, вставленная в Word, в частности (в настольном Word Windows), с использованием раскрывающегося списка «Цитаты и библиография» -> «Библиография» на ленте, выбрав встроенную запись «Библиография». То же самое и в Mac Word. В обоих есть элемент <w:bibliography/>. Так что, возможно, мы делаем что-то по-другому. Если вместо этого просто вставить поле {BIBLIOGRAPHY}, не будет ни структуры SDT, ни элемента <w:bibliography/>, а только обычная сложная структура поля с текстом поля, результатом поля и т. д.

jonsson 27.03.2024 13:00

Честно говоря, трудно понять, как удаление SDT не приводит к удалению библиографии, если библиография фактически не находится в SDT. Если вы еще не докопались до сути, было бы полезно опубликовать соответствующий XML до и после «удаления».

jonsson 27.03.2024 17:52

@jonsson Я добавил XML до и после

Charlie Clarke 21.05.2024 14:39

Честно говоря, самое простое объяснение этому состоит в том, что изменения в XmL фактически не были сохранены! Думаю, я бы разархивировал .docx и проверил.

jonsson 24.05.2024 09:16
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
8
91
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Я понял, что моя проблема заключалась в том, что я удалял только элементы w:sdt, которые были дочерними элементами элементов абзаца, а не основной элемент w:sdt библиографии. Удаление обоих необходимо, чтобы полностью избавиться от всей библиографии и ссылок на нее.

Для справки: ниже приведены инструкции по удалению ссылок на библиографию:

paragraph = ... # however you get the paragraph, maybe with `for paragraph in document.paragraphs`
p = paragraph._element
sdts = p.xpath('w:sdt')
for sdt in sdts:
    parent = sdt.getparent()
    parent.remove(sdt)

А ниже будет удален основной элемент библиографии:

body = doc._body._element
sdts = body.xpath("w:sdt")
if sdts:
    for sdt in sdts:
        parent = sdt.getparent()
        parent.remove(sdt)

Ха, потратил некоторое время на это и обнаружил, что ты опубликовал свой собственный ответ. Бывает! Но я опубликовал свой собственный, потому что он пытается удалить только наборы «Цитирование» и «Библиография», а не другие наборы, такие как «Контроль содержимого».

jonsson 24.05.2024 18:46

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

from docx import Document

# The xpaths to look for.
#   1. Citations,
#   2. The outer sdt of a Bibliography, then
#   3. In case there were bibliographies without the outer sdt,

# Of these, [2] probably needs to be tightened up as it's conceivable
# that a non-bibliography sdt could use a DocPart from the Bibliographies gallery.

xpaths = ("w:sdt[w:sdtPr/w:citation]",
          "w:sdt[w:sdtPr/w:docPartObj/w:docPartGallery[@w:val='Bibliographies']]",
          "w:sdt[w:sdtPr/w:bibliography]")

f = open('x.docx', 'rb')
document = Document(f)

p = document._body._element

for xp in xpaths:
    print(xp)
    sdts = p.xpath(xp)
    for sdt in sdts:
        sdt.getparent().remove(sdt)    

document.save('y.docx')
f.close()

Другие вопросы по теме