2

I've got a SVG file of the map of the US and I want to add colors to it. Because it would take me to much time, I thought I could use a bash script. I have also another file containing the states and the colors that belong to them.

SVG-file:

<g id="hi">
    <title>Hawaii</title>
    <path class="state hi" d="m 233.08751,519.30948 ... z" id="HI" />
</g>

CSV-file

HI, blue

What I want:

<g id="hi" style="fill:blue;">
        <title>Hawaii</title>
        <path class="state hi" d="m 233.08751,519.30948 ... z" id="HI" />
    </g>

I thought I could use grep or sed but I really don't know where to begin.

4 Answers 4

3

Using bash and GNU sed:

while IFS=",$IFS" read id color
do
    sed -i "s/g id=\"${id,,}\"/& style=\"fill:$color;\"/g" file.svg
done <file.csv

After this is done, file.svg looks like:

<g id="hi" style="fill:blue;">
    <title>Hawaii</title>
    <path class="state hi" d="m 233.08751,519.30948 ... z" id="HI" />
</g>

How it works

  • while IFS=",$IFS" read id color; do

    This starts a while loop by reading the variables id and color. We add a comma to IFS so that the input is split on commas as well as whitespace.

  • sed -i "s/g id=\"${id,,}\"/& style=\"fill:$color;\"/g" file.svg

    This does an in-place update of file.svg. This uses bash to convert id to lower case: ${id,,}. It looks for the string g id="${id,,}" and replaces it with g id="${id,,} style="fill:$color;".

    Note: $id and $color are substituted directly into a sed command. You should do this only if you trust the source of the file.csv file.

  • done <file.csv

    This concludes the while loop and instructs it to read from file.csv.

BSD (OSX)

If you are on a BSD system, we need to make a slight change to the sed command:

while IFS=",$IFS" read id color
do
    sed -i "" "s/g id=\"${id,,}\"/& style=\"fill:$color;\"/g" file.svg
done <file.csv
2
  • but the shell gives me this error: sed: -e expression #1, char 30: unterminated `s' command Nov 29, 2015 at 21:27
  • That would indicate a missing final /. Try copying-and-pasting again to make sure that the command is correct. Also, are you using the same file.csv in the question or a different one? If a different one, let me see the contents.
    – John1024
    Nov 29, 2015 at 21:32
2

Using Perl and its xsh :

perl {
    open my $FH, '<', 'states.csv' or die $!;
    $h->{lc $1} = "$2;" while <$FH> =~ /(.*),\s*(.*)/;
};

open map.xml ;
for //g set @style concat("fill:", xsh:lookup('h', @id));
save :b ;
1

using sed, twice:

</tmp/states.csv tr "[A-Z]" "[a-z]" | \
sed -n 's/^\([a-z]\{2\}\), \([^ ]*\)$/s@<g id="\1">@<g id="\1" style="fill:\2;">@/p' >/tmp/script.sed
sed -f /tmp/script.sed /tmp/source.svg

The first line creates a sed script (/tmp/script.sed) and the second line implements it. Assumes that your list of states is saved at /tmp/states.csv and your svg file at /tmp/source.svg.

1
  • @mikeserv, OP has told us what is in the csv, It could be modified to work if there is other stuff in the csv.
    – gogoud
    Nov 30, 2015 at 7:05
0
tr   \[:upper:] \[:lower:] <csv.file | sort -bt, -uk1,1   |
sed  -e'\|^ *\([[:alpha:]]\{2\}\) *, *\([[:alpha:]]\{1,\}\) *$|!d' \
     -e's||s/\\(<g id="\1"\\)>/\\1 style="fill:\2;">/;t|' |
sed  -f- svg.file

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .