Home > front end >  How to recursively add text to shapes to an existing .svg file with XSLT
How to recursively add text to shapes to an existing .svg file with XSLT

Time:10-13

I am totally new to XSLT, so please bear with me. I have svg files whose structure is as such:

<?xml-stylesheet type="text/xsl" href="TextAddition.xsl"?>

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="exportSvg" width="600" height="600">
<defs/>
<rect width="600" height="600" transform="translate(0, 0)" fill="rgb(255, 255, 255)" style="fill:rgb(255, 255, 255);"/>
<g>
<g id="Drawing-svg" clip-path="url(#rect-mask-Drawing)">
<clipPath id="rect-mask-Drawing">
<rect x="0" y="0" width="600" height="600"/>
</clipPath>
<g id="chart-svg">
<g id="svg-main" clip-path="url(#rect-mask-Main)">
<clipPath id="rect-mask-Main">
<rect x="0" y="0" width="600" height="600"/>
</clipPath>
<g id="Drawing-svg">
<g id="Parts-svg">
<g id="Section-svg">
<path d="M150 0 L75 200 L225 200 Z" stroke="rgb(100, 100, 100)" style="fill: rgb(100, 100, 100); stroke-width: 0.3; stroke-linejoin: round; stroke-linecap: round; stroke rgb(100, 100, 100);"/> 

<g id="symbols-svg">

<g id="Item1-svg" transform="translate(105, 210)">
<path d="M-5 0a5 5 0 1 0 10 0 5 5 0 1 0-10 0Z" stroke="rgb(200, 200, 200)" id="Item1" style="fill: rgb(0, 15, 60); stroke-width: 1; fill-opacity: 0.9; stroke-opacity: 0.5; stroke-linejoin: miter; stroke-linecap: butt; stroke: rgb(0, 50, 100);"/>
</g>

<g id="Item2-svg" transform="translate(250, 90)">
<path d="M-5 0a5 5 0 1 0 10 0 5 5 0 1 0-10 0Z" stroke="rgb(200, 200, 200)" id="Item2" style="fill: rgb(0, 15, 60); stroke-width: 1; fill-opacity: 0.9; stroke-opacity: 0.5; stroke-linejoin: miter; stroke-linecap: butt; stroke: rgb(0, 50, 100);"/>
</g>

</g>
</g>
</g>
</g>
</g>
</g>
</g>
</g>
</svg>

The resulting file I would like to have is this:

<?xml-stylesheet type="text/xsl" href="TextAddition.xsl"?>

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="exportSvg" width="600" height="600">
<defs/>
<rect width="600" height="600" transform="translate(0, 0)" fill="rgb(255, 255, 255)" style="fill:rgb(255, 255, 255);"/>
<g>
<g id="Drawing-svg" clip-path="url(#rect-mask-Drawing)">
<clipPath id="rect-mask-Drawing">
<rect x="0" y="0" width="600" height="600"/>
</clipPath>
<g id="chart-svg">
<g id="svg-main" clip-path="url(#rect-mask-Main)">
<clipPath id="rect-mask-Main">
<rect x="0" y="0" width="600" height="600"/>
</clipPath>
<g id="Drawing-svg">
<g id="Parts-svg">
<g id="Section-svg">
<path d="M150 0 L75 200 L225 200 Z" stroke="rgb(100, 100, 100)" style="fill: rgb(100, 100, 100); stroke-width: 0.3; stroke-linejoin: round; stroke-linecap: round; stroke rgb(100, 100, 100);"/> 

<g id="symbols-svg">

<g id="Item1-svg" transform="translate(105, 210)">
<path d="M-5 0a5 5 0 1 0 10 0 5 5 0 1 0-10 0Z" stroke="rgb(200, 200, 200)" id="Item1" style="fill: rgb(0, 15, 60); stroke-width: 1; fill-opacity: 0.9; stroke-opacity: 0.5; stroke-linejoin: miter; stroke-linecap: butt; stroke: rgb(0, 50, 100);"/>
<text x="" y="" id="Item1-text">
<tspan id="Item1-text" x="" y="" >Item1
</tspan>
</text>
</g>

<g id="Item2-svg" transform="translate(250, 90)">
<path d="M-5 0a5 5 0 1 0 10 0 5 5 0 1 0-10 0Z" stroke="rgb(200, 200, 200)" id="Item2" style="fill: rgb(0, 15, 60); stroke-width: 1; fill-opacity: 0.9; stroke-opacity: 0.5; stroke-linejoin: miter; stroke-linecap: butt; stroke: rgb(0, 50, 100);"/>
<text x="" y="" id="Item2-text">
<tspan id="Item2-text" x="" y="" >Item2
</tspan>
</g>

</g>
</g>
</g>
</g>
</g>
</g>
</g>
</g>
</svg>

In which, for each grouped Itemn part of the group symbols the following text block is added, being Itemn a match of name of the symbol it refers to. This is course a skeleton of the files I would like to work on, so there could be hundreds on Itemn and each of them would have its name displayed.

<text x="" y="" id="Itemn-text">
<tspan id="Itemn-text" x="" y="" >Itemn
</tspan>
</text>

And below the TextAddition.xsl

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns="http://www.w3.org/2000/svg" >
<xsl:output method="xml" indent="yes" standalone="no" doctype-public="-//W3C//DTD SVG 1.1//EN" doctype-system="http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" media-type="image/svg" />
<xsl:template match="/">
<xsl:for-each select="..."> <!-- Here-->
</xsl:template>
</xsl:stylesheet>

I am assuming the XSL file is well formed since i can see the file in the browser (code take from https://edutechwiki.unige.ch/en/XSLT_to_generate_SVG_tutorial) I understand I can modify it through XSLT, yet I do not know how to point to each of the symbols in order to add the text for each of them. Could someone please advise?

CodePudding user response:

For XSLT 3:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:svg="http://www.w3.org/2000/svg"
    xmlns="http://www.w3.org/2000/svg"
    exclude-result-prefixes="#all"
    version="3.0">
  
  <xsl:strip-space elements="*"/>
  
  <xsl:template match="svg:*[@id[starts-with(., 'Item')]]">
    <xsl:copy>
      <xsl:apply-templates select="@* | node()"/>
      <xsl:variable name="id" select="substring-before(@id, '-')"/>
      <text x="" y="" id="{$id}-text">
        <tspan id="{$id}-tspan" x="" y="">
          <xsl:value-of select="$id"/>
        </tspan>
      </text>
    </xsl:copy>
  </xsl:template>

  <xsl:mode on-no-match="shallow-copy"/>

</xsl:stylesheet>

For XSLT 1:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:svg="http://www.w3.org/2000/svg"
    xmlns="http://www.w3.org/2000/svg"
    exclude-result-prefixes="svg"
    version="1.0">
  
  <xsl:strip-space elements="*"/>
  
  <xsl:template match="svg:*[@id[starts-with(., 'Item')]]">
    <xsl:copy>
      <xsl:apply-templates select="@* | node()"/>
      <xsl:variable name="id" select="substring-before(@id, '-')"/>
      <text x="" y="" id="{$id}-text">
        <tspan id="{$id}-tspan" x="" y="">
          <xsl:value-of select="$id"/>
        </tspan>
      </text>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="@* | node()">
    <xsl:copy>
      <xsl:apply-templates select="@* | node()"/>
    </xsl:copy>
  </xsl:template>

</xsl:stylesheet>
  • Related