0

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?

Oran G. Utan
  • 455
  • 1
  • 2
  • 10
  • 1
    Use the identity transformation, then add templates for the elements you want to change (or perhaps templates for the comments you want to transform to SVG). – Martin Honnen Oct 12 '22 at 13:49
  • @MartinHonnen, thank you for the tip, however I am struggling to understand how I should do. It is not laziness in searching, it is literally I have almost no idea how to achieve what you are saying. Thank you for taking the time to write the code below. – Oran G. Utan Oct 12 '22 at 19:13

1 Answers1

1

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>
Martin Honnen
  • 160,499
  • 6
  • 90
  • 110
  • Thank you so much for replying, I tried the code (in Firefox) but I get the same drawing, without the block of text inserted. From what I understand the above is supposed to create comments? Maybe I was not clear in my question, I would like to add ``` Item1 ```, (with the text "Itemx" being taken from the symbol it refers to ) not the comment itself, that was supposed to mark the addition, forgive me if I was not clear. – Oran G. Utan Oct 12 '22 at 19:08
  • 1
    Consider to edit your question and to show at least two samples, the input XML you are going to transform with XSLT and the result you want after the XSLT transformation. Then explain where the additional data comes from and for which elements you want to add/generate that data. Is the sample you have shown just an example where you have added the text for one shape, but the task is to add it for more? – Martin Honnen Oct 12 '22 at 19:35
  • I have updated as suggested, basically for every Itemn there would be its name displayed. The data would come from the original .svg file itself. Thank you again :) – Oran G. Utan Oct 12 '22 at 19:52
  • 1
    @Bradipo, see whether the edit helps. – Martin Honnen Oct 12 '22 at 20:37
  • Thank you, in both cases the file opened in Firefox does not show the wanted text. I even tried adding `````` from your answer at https://stackoverflow.com/questions/28388064/xsltemplate-svg-namespace-disagreement-between-firefox-chrome , but nothing. I am starting to grasp something from the code you wrote, which is something good (although I am far away to be able to apply on my own...). I always thought xml would be easy somehow, I am learning the hard way it is not so... – Oran G. Utan Oct 12 '22 at 21:05
  • @Bradipo, it might be my fault, check whether added namespace helps. – Martin Honnen Oct 12 '22 at 21:35
  • Still nothing, I am using Firefox 105.0.3 (64-bit) under Linux , if it helps. – Oran G. Utan Oct 12 '22 at 21:50
  • 1
    The text shows up for me at https://martin-honnen.github.io/xslt/2022/test2022111201.xml. I added some sanity checks like not copying through the `xml-stylesheet` processing instruction but usually that shouldn't matter, only Opera at some point I think would literally chain XSLTs if the result contained another xml-stylesheet pi. – Martin Honnen Oct 12 '22 at 22:10
  • I was able to see the text from the linked files, yet when I saved them on my machine nothing was appearing. So there clearly is something with where the files are stored. Today I was reading that Chrome has limitations for XSL (https://stackoverflow.com/questions/4558160/xsl-not-working-in-google-chrome) and a way to bypass it is to save the files elsewhere, I would say Firefox is acting similarly (although at least the "raw" .svg is shown). As the code you wrote clearly works, I accepted your solution. Now the next part will come... integrate this into VBA. Thank you so much!!! :) – Oran G. Utan Oct 12 '22 at 22:37
  • @Bradipo, as for using `xml-stylesheet` to apply XSLT in an XML document loaded directly from the file system, unfortunately Firefox/Mozilla has preferred to disable that completely (following the precedent Chrome set) instead of fixing a security hole someone discovered exploiting the feature in some kind of web view or mobile version of Firefox. So unfortunately, you are forced to serve over HTTP to use that mechanism. – Martin Honnen Oct 13 '22 at 09:09