The conversion to SVG takes place in four steps:

break_path

This transformation takes the full path description and turns it into XML, one element per command. A typical output might be:

 <path style="stroke:blue" id="example">
  <M o="M" x="100" y="250" /> 
  <L o="L" x="125" y="275" /> 
  <H o="H" x="150" /> 
  <V o="V" y="250" /> 
  <M o="M" x="150" y="250" /> 
  <l o="l" x="25" y="25" /> 
  <h o="h" x="25" /> 
  <v o="v" y="-25" /> 
  <C o="C" r="215" u="275" v="235" w="225" x="250" y="250" /> 
  <S o="S" v="285" w="225" x="300" y="250" /> 
  <Q o="Q" v="325" w="275" x="350" y="250" /> 
  <T o="T" x="400" y="250" /> 
  <A o="A" g="20" b="20" d="1" e="0" f="0" x="450" y="250" /> 
  <a o="a" g="30" b="30" d="1" e="0" f="0" x="50" y="0" /> 
   <content>
  <set attributeName="id" to="'example'" begin="1s" /> 
  </content>
</path>

A major problem is handling what can be a very long d attribute (this can be over 1 Mbyte). To avoid very large internal variables, the string being worked on is always a small part of the total string. The next command's maximum length can be estimated given that the number of arguments to the command are known. Currently numbers with exponents are not catered for but it would be relatively easy to change if the need was there. The command recogniser is a finite state table that is optimised for numbers having several digits either before or after the decomal point. It runs significantly faster than a version based on regular expressions.

make_abs

Quite a straightforward recursive template that keeps a record of the last current position and possible Q and C control points. It uses this information to transform the next command into either an absolute cubic or a line. The appearance of a Z command is always preceded by an L command back to the initial point of the closed path. Each unclosed path is terminated by an E element and each Z followed by a drawing command has an M element inserted. The internal form of the commands is established here. Two attributes t and o give the internal type and the original type of the command. Each command includes attributes cx,cythat give the current position. The attributes x3,y3 always contain the end point that will be the next current position. The cubic command has additional attributes x1,y1,x2,y2. The arc command has additional attributes a,b,d,e,f. The attribute names are either one or two characters long to keep the file size down and each arithmetic computation rounds the number to 3 decimal places (this can be changed by the user). A typical output file might be:

<path style="stroke:blue" id="example">
  <c t="M" o="M" cx="0" cy="0" x3="100" y3="250" /> 
  <c t="L" o="L" cx="100" cy="250" x3="125" y3="275" /> 
  <c t="L" o="H" cx="125" cy="275" x3="150" y3="275" /> 
  <c t="L" o="V" cx="150" cy="275" x3="150" y3="250" /> 
  <c t="E" o="" cx="150" cy="250" /> 
  <c t="M" o="M" cx="150" cy="250" x3="150" y3="250" /> 
  <c t="L" o="l" cx="150" cy="250" x3="175" y3="275" /> 
  <c t="L" o="h" cx="175" cy="275" x3="200" y3="275" /> 
  <c t="L" o="v" cx="200" cy="275" x3="200" y3="250" /> 
  <c t="C" o="C" cx="200" cy="250" x1="215" y1="275" 
                 x2="235" y2="225" x3="250" y3="250" /> 
  <c t="C" o="S" cx="250" cy="250" x1="265" y1="275" 
                 x2="285" y2="225" x3="300" y3="250" /> 
  <c t="C" o="Q" cx="300" cy="250" x1="316.667" y1="266.667" 
                 x2="333.333" y2="266.667" x3="350" y3="250" /> 
  <c t="C" o="T" cx="350" cy="250" x1="366.667" y1="233.333" 
                 x2="383.333" y2="233.333" x3="400" y3="250" /> 
  <c t="A" o="A" cx="400" cy="250" a="20" b="20" d="1" e="0" 
                                      f="0" x3="450" y3="250" /> 
  <c t="A" o="a" cx="450" cy="250" a="30" b="30" d="1" e="0" 
                                      f="0" x3="500" y3="250" /> 
....
</path>

add_subpath

A simple transformation that inserts a subpath element s around each group starting with a command of type M. This is an XSLT2 transformation using the for-each-group function.

Typical output would be:

<path style="stroke:blue" id="example">
  <s>
  <c t="M" o="M" cx="0" cy="0" x3="100" y3="250" /> 
  <c t="L" o="L" cx="100" cy="250" x3="125" y3="275" /> 
  <c t="L" o="H" cx="125" cy="275" x3="150" y3="275" /> 
  <c t="L" o="V" cx="150" cy="275" x3="150" y3="250" /> 
  <c t="E" o="" cx="150" cy="250" /> 
</s>
<s>
  <c t="M" o="" cx="150" cy="250" x3="150" y3="250" /> 
  <c t="L" o="l" cx="150" cy="250" x3="250" y3="150" /> 
  <c t="L" o="h" cx="250" cy="150" x3="550" y3="150" /> 
  <c t="L" o="" cx="550" cy="150" x3="150" y3="250" /> 
  <c t="Z" o="Z" cx="150" cy="250" /> 
</s>
</path>

make_xml

Finally, this transformation makes the individual subpaths self-sufficient by changing M commands to N commands if the command starts an open subpath. The closing E command adds the current position of the next curve as x1,y1 attributes. This facilitates a straightforward function to do path reversal. The final form is something like:

  <path style="stroke:blue" id="example">
  <s>
  <c t="N" o="M" cx="0" cy="0" x3="101" y3="151" /> 
  <c t="L" o="h" cx="101" cy="151" x3="251" y3="151" /> 
  <c t="L" o="v" cx="251" cy="151" x3="251" y3="301" /> 
  <c t="L" o="h" cx="251" cy="301" x3="101" y3="301" /> 
  <c t="E" o="" cx="101" cy="301" x1="302" y1="152" /> 
  </s>
  <s>
  <c t="N" o="M" cx="101" cy="301" x3="302" y3="152" /> 
  <c t="L" o="h" cx="302" cy="152" x3="452" y3="152" /> 
  <c t="L" o="v" cx="452" cy="152" x3="452" y3="302" /> 
  <c t="L" o="h" cx="452" cy="302" x3="302" y3="302" /> 
  <c t="E" o="" cx="302" cy="302" x1="103" y1="353" /> 
  </s>
  <s>
  <c t="M" o="M" cx="302" cy="302" x3="103" y3="353" /> 
  <c t="L" o="h" cx="103" cy="353" x3="253" y3="353" /> 
  <c t="L" o="v" cx="253" cy="353" x3="253" y3="503" /> 
  <c t="L" o="h" cx="253" cy="503" x3="103" y3="503" /> 
  <c t="L" o="" cx="103" cy="503" x3="103" y3="353" /> 
  <c t="Z" o="Z" cx="103" cy="353" x1="304" y1="354" /> 
  </s>
  <s>
  <c t="M" o="M" cx="103" cy="353" x3="304" y3="354" /> 
  <c t="L" o="h" cx="304" cy="354" x3="454" y3="354" /> 
  <c t="L" o="v" cx="454" cy="354" x3="454" y3="504" /> 
  <c t="L" o="h" cx="454" cy="504" x3="304" y3="504" /> 
  <c t="L" o="" cx="304" cy="504" x3="304" y3="354" /> 
  <c t="Z" o="Z" cx="304" cy="354" x1="505" y1="155" /> 
  </s>
  <s>
  <c t="N" o="M" cx="304" cy="354" x3="505" y3="155" /> 
  <c t="L" o="h" cx="505" cy="155" x3="655" y3="155" /> 
  <c t="L" o="v" cx="655" cy="155" x3="655" y3="305" /> 
  <c t="L" o="h" cx="655" cy="305" x3="505" y3="305" /> 
  <c t="E" o="" cx="505" cy="305" x1="0" y1="0" /> 
  </s>
</path>