1
\$\begingroup\$

I'm attempting to parse an SVG file to get all of the colors that are present in the file. SVGs are XML based and their structure can vary a bit. For example:

<svg viewBox="-80 -80 160 160">
  <g stroke="black" fill="none">
    <path d='...' fill='#0FF'/>
    <path d='...' fill='#F0F'/>
    ...
  </g>
</svg>

and

<svg viewBox="0 0 100 100">
  <a>
    <path d="..." stroke="black" fill="red"/>
    <ellipse stroke="black" fill="white" cx="50" cy="40" rx="22" ry="35"/>
    <circle cx="50" cy="40" r="5" stroke="black" fill="red"/>
  </a>
</svg>

and

<svg viewBox="0 0 80 120">
  <rect id="background-rect" x="0%" y="0%" width="100%" height="100%" fill="#aaaaaa"/>
</svg>

Are all examples of valid SVGs. At first I attempted to create the underlying structs that would allow me to represent all of these structures but then I decided to take a more generic approach that would focus soley on the fill attribute which is all I care about:

type GenericNode struct {
    XMLName xml.Name
    Fill    string        `xml:"fill,attr"`
    Nodes   []GenericNode `xml:",any"`
}

func (s *SVGController) GetColorsFromXML() []string {
    xmlFile, _ := os.Open(s.Path)
    byteValue, _ := ioutil.ReadAll(xmlFile)
    var svg GenericNode
    xml.Unmarshal(byteValue, &svg)

    // Using a map here to avoid having to worry about having
    // duplicate colors in the color slice
    colorMap := make(map[string]struct{})
    colorMap = getSVGColors(svg, colorMap)

    // Once we have a complete color map extract all the keys
    // to an array and return it.
    colors := make([]string, len(colorMap))
    i := 0
    for k := range colorMap {
        colors[i] = k
        i++
    }
    return colors
}

func getSVGColors(svg GenericNode, colors map[string]struct{}) map[string]struct{} {
    if svg.Fill != "" && strings.ToLower(svg.Fill) != "none" {
        colors[svg.Fill] = struct{}{}
    }
    for _, node := range svg.Nodes {
        colors = getSVGColors(node, colors)
    }
    return colors
}

Is this a reasonable approach to take? Am I doing anything here that should be avoided?

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.