I would like to set the fill opacity of all paths whose id starts with Invisible to 0.0, below the SVG.
Original SVG (extract)
<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="Invisible2-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="Invisible2" 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="Invisible3-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="Invisible3" 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>
Here is the XSL I used , I tried editing what I could find at How to modify a SVG attribute using XSLT
XSL for the relative task
<xsl:template match="svg:*[@id[starts-with(., 'Invisible')]]">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:attribute name="fill-opacity">0.0</xsl:attribute>
<xsl:apply-templates select="node()"/>
</xsl:copy>
</xsl:copy>
</xsl:template>
Yet I only get the wanted paths duplicated, and with fill-opacity not as a style but as something that does not have real effect on the path.
Resulting (wrong) 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="Invisible2-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="Invisible2" 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);" fill-opacity="0.0;" />
</g>
<g id="Invisible3-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="Invisible3" 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);" fill-opacity="0.0;" />
</g>
</g>
</g>
Wanted result 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="Invisible2-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="Invisible2" style="fill: rgb(0, 15, 60); stroke-width: 1; fill-opacity: 0.0; stroke-opacity: 0.5; stroke-linejoin: miter; stroke-linecap: butt; stroke: rgb(0, 50, 100);" />
</g>
<g id="Invisible3-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="Invisible3" style="fill: rgb(0, 15, 60); stroke-width: 1; fill-opacity: 0.0; stroke-opacity: 0.5; stroke-linejoin: miter; stroke-linecap: butt; stroke: rgb(0, 50, 100);" />
</g>
</g>
</g>
I also tried matching the path and giving it the style I would like it to have
XSL
<xsl:template match="svg:path[@id[starts-with(., 'Invisible')]]">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
<xsl:copy>
<xsl:apply-templates select="@*"/>
<path style="fill: rgb(0, 15, 60); stroke-width: 0.1; fill-opacity: 0.0; stroke-opacity: 0.0; stroke-linejoin: miter; stroke-linecap: butt; stroke: rgb(0, 50, 100);">
<xsl:apply-templates select="node()"/>
</xsl:copy>
</xsl:copy>
</xsl:template>
but both NotePad and VBA said the resulting XSL is not well formed.
Nor did this work
XSL
<xsl:template match="svg:*[@id[starts-with(., 'Invisible')]]">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:attribute style="fill-opacity">0.0</xsl:attribute>
<xsl:apply-templates select="node()"/>
</xsl:copy>
</xsl:copy>
</xsl:template>
Could someone please advise?
CodePudding user response:
If I am guessing correctly, you want to change the existing fill-opacity
value inside the existing style
attribute. If so, try something like:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:svg="http://www.w3.org/2000/svg">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<!-- identity transform -->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="svg:*[starts-with(@id, 'Invisible')]/@style">
<xsl:attribute name="style">
<xsl:value-of select="substring-before(., 'fill-opacity:')" />
<xsl:text>fill-opacity: 0.0;</xsl:text>
<xsl:value-of select="substring-after(substring-after(., 'fill-opacity:'), ';')" />
</xsl:attribute>
</xsl:template>
</xsl:stylesheet>
CodePudding user response:
You've got two xsl:copy
elements inside the template that matches "Invisible" elements; hence the duplication. You want to copy the element once, copy its attributes, then create the new fill-opacity
attribute, then apply templates to copy child nodes (and descendants, recursively).
Try this:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:svg="http://www.w3.org/2000/svg"
exclude-result-prefixes="svg"
version="1.0">
<xsl:output method="xml" encoding="utf-8" omit-xml-declaration="yes"/>
<xsl:template match="svg:*[@id[starts-with(., 'Invisible')]]">
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:attribute name="fill-opacity">0.0</xsl:attribute>
<xsl:apply-templates select="node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
BTW your well-formedness error is because your SVG path
element is not closed.
CodePudding user response:
Here's a refinement of Michael's answer, which will work correctly even if the element has no existing style
attribute, or has a style
attribute which doesn't already contain a fill-opacity
property.
It works slightly differently in that it has a template that matches an element whose id
attribute starts with Invisible
, rather than directly matching the style
attribute of such an element.
The template copies the "invisible" element, and its attributes, and then constructs a new style
attribute that starts with fill-opacity:0.0;
, and then finishes in one of two different ways: if there was an existing style
containing a fill-opacity
property, then it copies the parts before and after that fill-opacity
property, but otherwise it copies the entire value of the style
attribute.
The reason for doing it in two different ways is that the functions substring-before
and substring-after
will return empty strings if the substring being sought (i.e. fill-opacity:
is not in the string, and that would have the effect of erasing all the other CSS properties in the style
attribute.
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:svg="http://www.w3.org/2000/svg">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<!-- identity transform -->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*[starts-with(@id, 'Invisible')]">
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:attribute name="style">
<xsl:text>fill-opacity: 0.0;</xsl:text>
<xsl:choose>
<xsl:when test="contains(@style, 'fill-opacity')">
<!-- style already contains a fill-opacity property, so
it's safe to use substring-before and substring-after to
extract the preceding and following CSS properties -->
<xsl:value-of select="
concat(
substring-before(
@style,
'fill-opacity:'
),
substring-after(
substring-after(
@style,
'fill-opacity:'
),
';'
)
)
"/>
</xsl:when>
<xsl:otherwise>
<!-- style had no existing fill-opacity property
so just copy the whole text including any other CSS properties -->
<xsl:value-of select="@style"/>
</xsl:otherwise>
</xsl:choose>
</xsl:attribute>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>