Редактирование SVG-элементов с CSS-селекторами в Python

Краткий ответ: Чтобы редактировать SVG-элементы с CSS-селекторами в Python, загрузите файл через SVGDocument, найдите одну редактируемую цель через Element.query_selector() или несколько узлов через Element.query_selector_all(), обновите атрибуты у одного найденного элемента или содержимое уровня узла, например text_content, у нескольких совпадений, и сохраните SVG.

1from aspose.svg import SVGDocument
2
3with SVGDocument("document.svg") as document:
4    element = document.root_element.query_selector("#target")
5    if element is not None:
6        element.set_attribute("fill", "#2e86de")
7    document.save("edited.svg")

CSS-селекторы удобны, когда SVG-файл содержит понятные ID, классы, атрибуты или вложенные группы. Идея проста: написать селектор, который указывает на нужный SVG-элемент, обновить этот элемент и сохранить документ.

В этой статье вы узнаете, как:

Статья посвящена редактированию через селекторы. Более широкие примеры проверки документа, обхода дерева и XPath смотрите в статье Навигация по SVG в Python.

Пример SVG, используемый в статье

В статье используется файл css-selectors-edit.svg. В примерах этот файл используется как data/css-selectors-edit.svg. Пример SVG содержит три небольшие редактируемые группы: #badge, #status-card и #chart. Примеры ниже показывают, как селекторы указывают на реальные части SVG перед изменением кода.

Как редактировать SVG-элементы с CSS-селекторами в Python

Используйте этот сценарий, когда SVG-файл имеет стабильные ID, классы, атрибуты или вложенные группы:

  1. Загрузите SVG-файл с помощью SVGDocument.
  2. Выберите самый узкий селектор, который определяет цель: #id, .class, tag[attribute] или ограниченный селектор внутри группы.
  3. Используйте query_selector() для одного редактируемого элемента, когда нужен set_attribute().
  4. Используйте query_selector_all() только для безопасных правок уровня node по множеству совпадений, например для text_content.
  5. Сохраните отредактированный SVG и проверьте, что селектор не затронул лишние элементы.

Редактирование одного SVG-элемента по ID

ID-селектор – самый простой и безопасный вариант, когда целевой элемент уникален. Следующий пример находит круг с id="badge-bg", меняет fill, stroke и stroke-width и сохраняет отредактированный SVG как css-selector-edit-by-id.svg. Используйте этот прием для SVG-шаблонов, где важные объекты имеют стабильные ID.

 1import os
 2from aspose.svg import SVGDocument
 3
 4input_folder = "data/"
 5output_folder = "output/"
 6input_path = os.path.join(input_folder, "css-selectors-edit.svg")
 7output_path = os.path.join(output_folder, "css-selector-edit-by-id.svg")
 8os.makedirs(output_folder, exist_ok=True)
 9
10with SVGDocument(input_path) as document:
11    badge_background = document.root_element.query_selector("#badge-bg")
12
13    if badge_background is not None:
14        badge_background.set_attribute("fill", "#2e86de")
15        badge_background.set_attribute("stroke", "#0d47a1")
16        badge_background.set_attribute("stroke-width", "5")
17
18    document.save(output_path)

Изображение ниже сравнивает исходный SVG (a) с css-selector-edit-by-id.svg (b). Меняются только цвет и контур круга, выбранного #badge-bg; карточка статуса, диаграмма и подписи остаются без изменений.

Исходный SVG и результат после изменения круга бейджа по ID

Редактирование нескольких SVG-текстов по классу

Используйте query_selector_all(), когда одинаковая правка уровня node должна примениться ко всем совпадениям. Пример SVG использует class="label" для всех текстовых подписей. Следующий пример находит все labels и обновляет их текст.

 1import os
 2from aspose.svg import SVGDocument
 3
 4input_folder = "data/"
 5output_folder = "output/"
 6input_path = os.path.join(input_folder, "css-selectors-edit.svg")
 7output_path = os.path.join(output_folder, "css-selector-edit-labels.svg")
 8os.makedirs(output_folder, exist_ok=True)
 9
10with SVGDocument(input_path) as document:
11    labels = document.root_element.query_selector_all(".label")
12
13    for label in labels:
14        label.text_content = label.text_content.upper()
15
16    document.save(output_path)

Выходной файл меняет текст каждого текстового SVG-узла с классом label. Это основной пример для нескольких узлов в статье: он использует query_selector_all() для сценария работы с селекторами и не вызывает Element.set_attribute() для элементов NodeList.

Изображение ниже сравнивает исходный SVG (a) с результатом css-selector-edit-labels.svg (b). Все подписи переведены в верхний регистр, а фигуры, fill, stroke и столбцы диаграммы остаются прежними.

Исходный SVG и результат после изменения текстовый SVG-узелs по классу

Использование ограниченных селекторов атрибутов

Ограниченные селекторы атрибутов полезны, когда широкий селектор совпал бы со слишком многими элементами. Следующий пример редактирует две разные цели в одном сценарии: индикатора статуса, выбранный #status-card circle[fill], и высокий столбец диаграммы, выбранный #chart .bar[data-level='high'].

 1import os
 2from aspose.svg import SVGDocument
 3
 4input_folder = "data/"
 5output_folder = "output/"
 6input_path = os.path.join(input_folder, "css-selectors-edit.svg")
 7output_path = os.path.join(output_folder, "css-selector-edit-scoped-attributes.svg")
 8os.makedirs(output_folder, exist_ok=True)
 9
10with SVGDocument(input_path) as document:
11    warning_dot = document.root_element.query_selector("#status-card circle[fill]")
12    high_bar = document.root_element.query_selector("#chart .bar[data-level='high']")
13
14    if warning_dot is not None:
15        warning_dot.set_attribute("fill", "#d32f2f")
16        warning_dot.set_attribute("stroke", "#8b0000")
17        warning_dot.set_attribute("stroke-width", "4")
18
19    if high_bar is not None:
20        high_bar.set_attribute("fill", "#455a64")
21        high_bar.set_attribute("opacity", "1")
22
23    document.save(output_path)

Первый селектор находит круг только внутри #status-card и только если у него есть атрибут fill. Второй селектор находит столбец диаграммы, у которого data-level равен high. В результате должны появиться красный индикатор статуса и темный высокий столбец.

Изображение ниже сравнивает исходный SVG (a) с css-selector-edit-scoped-attributes.svg (b). Ограниченные селекторы обновляют две отдельные цели, не меняя бейдж или нижние столбцы диаграммы. В этом главное преимущество сочетания группы, класса, тега и условий по атрибутам.

Исходный SVG и результат после изменения индикатора статуса и высокого столбца диаграммы

Частые ошибки и исправления

Для обновления атрибутов предпочитайте query_selector() с селектором, который указывает на один редактируемый элемент. Для повторяющегося текста или правок уровня узла используйте query_selector_all() и обрабатывайте каждый возвращенный узел. Делайте селекторы стабильными: ID лучше всего подходят для уникальных частей шаблона, классы полезны для повторяющихся подписей, а ограниченные селекторы помогают не менять похожие элементы в других группах.

ПроблемаИсправление
Меняется только одна цельquery_selector() возвращает только первое совпадение. Используйте query_selector_all() для правок нескольких узлов, например изменения text_content; используйте query_selector(), когда коду нужен set_attribute().
set_attribute() падает внутри цикла query_selector_all()Элементы NodeList могут не предоставлять Element.set_attribute(). Используйте правки уровня узла, например text_content, или query_selector(), когда нужно задавать атрибуты.
Селектор ничего не возвращаетПроверьте исходный SVG и реальные ID, классы, имена тегов и значения атрибутов.
Селектор атрибута не совпадаетНачните с селектора на наличие атрибута, например circle[fill], и добавляйте фильтры по значению только после того, как простой селектор заработал.
Широкий селектор класса меняет слишком многоДобавьте контекст, например #chart .bar[data-level='high'], чтобы ограничить правку одной группой.
Выходной файл не изменилсяСохраните отредактированный документ и откройте выходной файл, а не исходный входной файл.

FAQ

Можно ли использовать CSS-селекторы для редактирования SVG в Python?

Да. Загрузите SVG с помощью SVGDocument, найдите одну редактируемую цель через query_selector() и обновите ее с помощью set_attribute(). Используйте query_selector_all(), когда нужно обработать все совпадающие узлы через правку уровня узла, например изменить text_content.

В чем разница между query_selector() и query_selector_all()?

query_selector() возвращает первый совпавший элемент и подходит, когда код должен вызвать set_attribute(). query_selector_all() возвращает NodeList всех совпадений и полезен для правки уровня узла, например изменения text_content у всех найденных текстовых узлов.

Можно ли выбирать SVG-элементы по классу?

Да. Используйте селектор класса, например .label. Для нескольких текстовых узлов query_selector_all(".label") может обновить text_content у каждого совпадения. Для задания атрибутов используйте ограниченный селектор с query_selector().

Можно ли выбирать SVG-элементы по атрибутам?

Да. Селекторы атрибутов вроде circle[fill] или .bar[data-level='high'] могут находить SVG-элементы по существующим атрибутам. Ограничивайте их ID группы, если такой же шаблон встречается в нескольких местах.

Что выбрать для редактирования SVG – CSS-селекторы или XPath?

Используйте CSS-селекторы для ID, классов, атрибутов и простых правок внутри группы. Используйте XPath, когда запрос зависит от более сложной структуры документа или отношений между узлами.

Связанные статьи