在 Python 中用 CSS 选择器编辑 SVG 元素

快速回答: 要在 Python 中用 CSS 选择器编辑 SVG 元素,请用 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")

当 SVG 文件包含有意义的 ID、class、属性或嵌套组时,CSS 选择器很有用。思路很简单:写一个指向目标 SVG 元素的选择器,更新该元素,然后保存文档。

在本文中,你将学习如何:

本文关注基于选择器的编辑工作流。更广泛的文档检查、树遍历和 XPath 示例,请参阅 在 Python 中导航 SVG

示例中使用的 SVG

本文使用示例文件 css-selectors-edit.svg。运行示例前,可以将它作为 data/css-selectors-edit.svg 使用。该示例 SVG 包含三个可编辑的小组:#badge#status-card#chart。下面的示例使用这些组来展示选择器如何在代码修改它们之前指向真实 SVG 部分。

如何在 Python 中用 CSS 选择器编辑 SVG 元素

当 SVG 文件具有稳定 ID、class、属性或嵌套组时,可以使用这个工作流:

  1. SVGDocument 加载 SVG 文件。
  2. 选择能识别目标的最窄选择器,例如 #id.classtag[attribute],或组内的 scoped selector。
  3. 当需要 set_attribute() 时,对一个可编辑元素使用 query_selector()
  4. 仅在适合跨多个匹配项执行安全节点级编辑时使用 query_selector_all(),例如修改 text_content
  5. 保存编辑后的 SVG,并确认选择器没有影响无关元素。

按 ID 编辑一个 SVG 元素

当目标元素唯一时,ID 选择器是最简单、最安全的选择。下面的示例找到 id="badge-bg" 的圆,修改它的填充和轮廓,并把编辑后的 SVG 保存为 css-selector-edit-by-id.svg。对于重要对象具有稳定 ID 的模板 SVG,可以使用这种模式。

 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 修改 badge 圆后的编辑结果

按 Class 编辑多个 SVG 文本节点

当同一种节点级编辑应应用到每个匹配项时,可以使用 query_selector_all()。示例 SVG 在所有文本标签上使用 class="label"。下面的示例找到所有标签并更新它们的文本内容。

 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)

输出会修改每个 class 为 label 的 SVG 文本节点。这个示例是本文的主要多节点示例:它使用 query_selector_all() 完成选择器工作流,并避免在 NodeList 项上调用 Element.set_attribute()

下图比较源 SVG (a) 与保存为 css-selector-edit-labels.svg 的结果 (b)。所有标签文本都变为大写,而形状、填充、描边和图表柱保持不变,因此视觉重点集中在基于 class 的文本编辑上。

原始 SVG 与按 class 修改 SVG 文本节点后的编辑结果

使用 Scoped Attribute Selectors

当宽泛选择器会匹配过多内容时,scoped attribute selectors 很有用。下面的示例在一个工作流中编辑两个不同目标:由 #status-card circle[fill] 选中的状态圆点,以及由 #chart .bar[data-level='high'] 选中的 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 的图表柱。输出应显示红色状态圆点和深色 high 图表柱。

下图比较源 SVG (a) 与 css-selector-edit-scoped-attributes.svg (b)。scoped selectors 会更新两个独立目标,而不会改变 badge 或较低的图表柱;这正是组合 group、class、tag 和 attribute 条件的主要优势。

原始 SVG 与修改状态圆点和 high 图表柱后的编辑结果

常见错误和修复

对于属性更新,优先使用 query_selector(),并让选择器指向一个可编辑元素。对于重复文本或节点级修改,使用 query_selector_all() 并逐个处理返回节点。保持选择器稳定:ID 最适合唯一模板部件,class 适合重复标签,scoped selectors 有助于避免修改其他组中的相似元素。

问题修复
只有一个目标改变query_selector() 只返回第一个匹配项。对于修改 text_content 这类多节点编辑,使用 query_selector_all();当代码必须调用 set_attribute() 时,使用 query_selector()
query_selector_all() 循环中调用 set_attribute() 失败NodeList 项可能不公开 Element.set_attribute()。请使用 text_content 这类节点级编辑,或在需要设置属性时使用 query_selector()
选择器返回空结果检查 SVG 源文件,确认真实 ID、class、标签名和属性值。
属性选择器不匹配先从 circle[fill] 这类属性存在选择器开始,简单选择器生效后再添加值过滤。
宽泛 class 选择器修改过多内容添加上下文,例如 #chart .bar[data-level='high'],把编辑限制在一个组内。
输出文件没有变化保存编辑后的文档,并打开输出路径,而不是原始输入文件。

FAQ

可以在 Python 中用 CSS 选择器编辑 SVG 吗?

可以。用 SVGDocument 加载 SVG,用 query_selector() 找到一个可编辑目标,并用 set_attribute() 更新它。当需要用节点级编辑处理所有匹配节点时,例如修改 text_content,可以使用 query_selector_all()

query_selector() 和 query_selector_all() 有什么区别?

query_selector() 返回第一个匹配元素,当代码必须调用 set_attribute() 时应使用它。query_selector_all() 返回所有匹配项的 NodeList,适合对每个匹配文本节点修改 text_content 这类节点级编辑。

可以按 class 选择 SVG 元素吗?

可以。使用 .label 这类 class 选择器。对于多个文本节点,query_selector_all(".label") 可以更新每个匹配项的 text_content。如果要设置属性,请使用带范围的选择器并配合 query_selector()

可以按属性选择 SVG 元素吗?

可以。circle[fill].bar[data-level='high'] 这类属性选择器可以按已有属性定位 SVG 元素。当同一模式出现在多个位置时,请用组 ID 限定范围。

SVG 编辑应该使用 CSS 选择器还是 XPath?

对于 ID、class、属性以及简单的组内编辑,使用 CSS 选择器。对于依赖更复杂文档结构或节点关系的查询,使用 XPath。

相关文章