Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Provide Access to Parents and Other Tags (diff) #209

Open
bcwhite-code opened this issue May 31, 2023 · 0 comments
Open

Provide Access to Parents and Other Tags (diff) #209

bcwhite-code opened this issue May 31, 2023 · 0 comments

Comments

@bcwhite-code
Copy link

In processing an SVG file in preparation for display, I find myself in need of information from parent "g" tags as well as the global "style" tag. What do you think of this change that allows for exporting all that information to the caller?

diff --git a/svgpathtools/svg_to_paths.py b/svgpathtools/svg_to_paths.py
index 65591af..9edf200 100644
--- a/svgpathtools/svg_to_paths.py
+++ b/svgpathtools/svg_to_paths.py
@@ -3,7 +3,7 @@ The main tool being the svg2paths() function."""

 # External dependencies
 from __future__ import division, absolute_import, print_function
-from xml.dom.minidom import parse
+from xml.dom.minidom import parse, Node
 import os
 from io import StringIO
 import re
@@ -136,6 +136,8 @@ def line2pathd(l):

 def svg2paths(svg_file_location,
               return_svg_attributes=False,
+              return_other_tags=None,
+              include_parent_info=False,
               convert_circles_to_paths=True,
               convert_ellipses_to_paths=True,
               convert_lines_to_paths=True,
@@ -182,61 +184,86 @@ def svg2paths(svg_file_location,

     doc = parse(svg_file_location)

-    def dom2dict(element):
-        """Converts DOM elements to dictionaries of attributes."""
-        keys = list(element.attributes.keys())
-        values = [val.value for val in list(element.attributes.values())]
+    def dom2dict(element, include_parents=False):
+        """Converts DOM elements to dictionaries of attributes, including parent information."""
+        if element.attributes is not None:
+            keys = list(element.attributes.keys())
+            values = [val.value for val in list(element.attributes.values())]
+        else:
+            keys = []
+            values = []
+        if include_parents:
+            keys.append('_tag')
+            values.append(element.tagName)
+            parent = element.parentNode
+            if parent is not None and parent.nodeType == Node.ELEMENT_NODE and parent.tagName != 'svg':
+                keys.append('_parent')
+                values.append(dom2dict(parent, True))
         return dict(list(zip(keys, values)))

+    # Short name for all the dom2dict calls below
+    ip = include_parent_info
+
     # Use minidom to extract path strings from input SVG
-    paths = [dom2dict(el) for el in doc.getElementsByTagName('path')]
+    paths = [dom2dict(el,ip) for el in doc.getElementsByTagName('path')]
     d_strings = [el['d'] for el in paths]
     attribute_dictionary_list = paths

     # Use minidom to extract polyline strings from input SVG, convert to
     # path strings, add to list
     if convert_polylines_to_paths:
-        plins = [dom2dict(el) for el in doc.getElementsByTagName('polyline')]
+        plins = [dom2dict(el,ip) for el in doc.getElementsByTagName('polyline')]
         d_strings += [polyline2pathd(pl) for pl in plins]
         attribute_dictionary_list += plins

     # Use minidom to extract polygon strings from input SVG, convert to
     # path strings, add to list
     if convert_polygons_to_paths:
-        pgons = [dom2dict(el) for el in doc.getElementsByTagName('polygon')]
+        pgons = [dom2dict(el,ip) for el in doc.getElementsByTagName('polygon')]
         d_strings += [polygon2pathd(pg) for pg in pgons]
         attribute_dictionary_list += pgons

     if convert_lines_to_paths:
-        lines = [dom2dict(el) for el in doc.getElementsByTagName('line')]
+        lines = [dom2dict(el,ip) for el in doc.getElementsByTagName('line')]
         d_strings += [('M' + l['x1'] + ' ' + l['y1'] +
                        'L' + l['x2'] + ' ' + l['y2']) for l in lines]
         attribute_dictionary_list += lines

     if convert_ellipses_to_paths:
-        ellipses = [dom2dict(el) for el in doc.getElementsByTagName('ellipse')]
+        ellipses = [dom2dict(el,ip) for el in doc.getElementsByTagName('ellipse')]
         d_strings += [ellipse2pathd(e) for e in ellipses]
         attribute_dictionary_list += ellipses

     if convert_circles_to_paths:
-        circles = [dom2dict(el) for el in doc.getElementsByTagName('circle')]
+        circles = [dom2dict(el,ip) for el in doc.getElementsByTagName('circle')]
         d_strings += [ellipse2pathd(c) for c in circles]
         attribute_dictionary_list += circles

     if convert_rectangles_to_paths:
-        rectangles = [dom2dict(el) for el in doc.getElementsByTagName('rect')]
+        rectangles = [dom2dict(el,ip) for el in doc.getElementsByTagName('rect')]
         d_strings += [rect2pathd(r) for r in rectangles]
         attribute_dictionary_list += rectangles

+    path_list = [parse_path(d) for d in d_strings]
+    retval = [path_list, attribute_dictionary_list]
+
     if return_svg_attributes:
         svg_attributes = dom2dict(doc.getElementsByTagName('svg')[0])
-        doc.unlink()
-        path_list = [parse_path(d) for d in d_strings]
-        return path_list, attribute_dictionary_list, svg_attributes
-    else:
-        doc.unlink()
-        path_list = [parse_path(d) for d in d_strings]
-        return path_list, attribute_dictionary_list
+        retval.append(svg_attributes)
+
+    if return_other_tags is not None:
+        other_tags = {}
+        for other in return_other_tags:
+            other_tags[other] = []
+            elements = doc.getElementsByTagName(other)
+            for el in elements:
+                taginfo = dom2dict(el,ip)
+                taginfo['_value'] = el.firstChild.nodeValue if el.firstChild is not None else None
+                other_tags[other].append(taginfo)
+        retval.append(other_tags)
+
+    doc.unlink()
+    return retval


 def svg2paths2(svg_file_location,
@@ -262,6 +289,8 @@ def svg2paths2(svg_file_location,

 def svgstr2paths(svg_string,
                return_svg_attributes=False,
+               return_other_tags=None,
+               include_parent_info=False,
                convert_circles_to_paths=True,
                convert_ellipses_to_paths=True,
                convert_lines_to_paths=True,
@@ -275,6 +304,8 @@ def svgstr2paths(svg_string,
     svg_file_obj = StringIO(svg_string)
     return svg2paths(svg_file_location=svg_file_obj,
                      return_svg_attributes=return_svg_attributes,
+                     return_other_tags=return_other_tags,
+                     include_parent_info=include_parent_info,
                      convert_circles_to_paths=convert_circles_to_paths,
                      convert_ellipses_to_paths=convert_ellipses_to_paths,
                      convert_lines_to_paths=convert_lines_to_paths,

I can create a pull request if you don't think any changes are necessary.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant