Convert svg to embedded svg with XSLT
Here should go questions about transforming XML with XSLT and FOP.
-
- Posts: 8
- Joined: Mon Nov 26, 2018 12:56 am
Convert svg to embedded svg with XSLT
Hi,
I would like to convert a svg file opened in Oxygen with xslt so that I can copy and paste it into a DITA svg container.
The xslt brings only limited success and some additional manual work is unfortunately required.
Example file:
Desired result:
1. remove namespace declartion in root element
2. add namespace prefix for all elements (svg:)
3. remove @id in all elements, except in linearGradient
4. remove tspan in text
Current result (namespace in root element and tspan are not removed):
My XSLT:
The if-query is certainly messy. But I couldn't do it any other way. Templates for concrete elements don't seem to do anything at all.
Can anyone give me tips on what I'm doing wrong?
Thanks a lot
Regards
Apollo
I would like to convert a svg file opened in Oxygen with xslt so that I can copy and paste it into a DITA svg container.
The xslt brings only limited success and some additional manual work is unfortunately required.
Example file:
Code: Select all
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 919 647" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<g transform="matrix(1,0,0,1,-214.985,-499.215)">
<g id="Alles">
<g id="Test">
<rect x="535.908" y="574.988" width="387.783" height="222.864" style="fill:rgb(235,235,235);"/>
<circle cx="976.064" cy="897.026" r="152.662" style="fill:rgb(235,235,235);"/>
</g>
<rect x="576.024" y="1020.72" width="557.159" height="124.804" style="fill:url(#_Linear1);"/>
</g>
</g>
<text x="166.628px" y="336.867px" style="font-family:'ArialMT', 'Arial', sans-serif;font-size:33.333px;">Audit-T<tspan x="272.829px 283.929px " y="336.867px 336.867px ">ra</tspan>il</text>
<defs>
<linearGradient id="_Linear1" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(557.159,0,0,124.804,576.024,1083.12)"><stop offset="0" style="stop-color:black;stop-opacity:1"/><stop offset="1" style="stop-color:rgb(235,235,235);stop-opacity:1"/></linearGradient>
</defs>
</svg>
1. remove namespace declartion in root element
2. add namespace prefix for all elements (svg:)
3. remove @id in all elements, except in linearGradient
4. remove tspan in text
Code: Select all
<svg:svg width="100%" height="100%" viewBox="0 0 919 647" version="1.1" xml:space="preserve" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;" preserveAspectRatio="xMidYMid meet" zoomAndPan="magnify" contentScriptType="text/ecmascript" contentStyleType="text/css">
<svg:g transform="matrix(1,0,0,1,-214.985,-499.215)">
<svg:g>
<svg:g>
<svg:rect x="535.908" y="574.988" width="387.783" height="222.864" style="fill:rgb(235,235,235);"/>
<svg:circle cx="976.064" cy="897.026" r="152.662" style="fill:rgb(235,235,235);"/>
</svg:g>
<svg:rect x="576.024" y="1020.72" width="557.159" height="124.804" style="fill:url(#_Linear1);"/>
</svg:g>
</svg:g>
<svg:text x="166.628px" y="336.867px" style="font-family:'ArialMT', 'Arial', sans-serif;font-size:33.333px;">Audit-Trail</svg:text>
<svg:defs>
<svg:linearGradient id="_Linear1" x1="0" y1="0" x2="1" y2="0" xlink:type="simple" xlink:show="other" xlink:actuate="onLoad"><svg:stop offset="0" style="stop-color:black;stop-opacity:1"/><svg:stop offset="1" style="stop-color:rgb(235,235,235);stop-opacity:1"/></svg:linearGradient>
</svg:defs>
</svg:svg>
Current result (namespace in root element and tspan are not removed):
Code: Select all
<svg:svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:serif="http://www.serif.com/" xmlns:svg="http://www.w3.org/2000/svg" width="100%" height="100%" viewBox="0 0 919 647" version="1.1" xml:space="preserve" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;" preserveAspectRatio="xMidYMid meet" zoomAndPan="magnify" contentScriptType="text/ecmascript" contentStyleType="text/css">
<svg:g transform="matrix(1,0,0,1,-214.985,-499.215)">
<svg:g>
<svg:g>
<svg:rect x="535.908" y="574.988" width="387.783" height="222.864" style="fill:rgb(235,235,235);"/>
<svg:circle cx="976.064" cy="897.026" r="152.662" style="fill:rgb(235,235,235);"/>
</svg:g>
<svg:rect x="576.024" y="1020.72" width="557.159" height="124.804" style="fill:url(#_Linear1);"/>
</svg:g>
</svg:g>
<svg:text x="166.628px" y="336.867px" style="font-family:'ArialMT', 'Arial', sans-serif;font-size:33.333px;">Audit-T<svg:tspan x="272.829px 283.929px " y="336.867px 336.867px ">ra</svg:tspan>il</svg:text>
<svg:defs>
<svg:linearGradient id="_Linear1" x1="0" y1="0" x2="1" y2="0" xlink:type="simple" xlink:show="other" xlink:actuate="onLoad"><svg:stop offset="0" style="stop-color:black;stop-opacity:1"/><svg:stop offset="1" style="stop-color:rgb(235,235,235);stop-opacity:1"/></svg:linearGradient>
</svg:defs>
</svg:svg>
My XSLT:
Code: Select all
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xlink="http://www.w3.org/1999/xlink/"
xmlns:svg="http://www.w3.org/2000/my/"
xmlns:serif="http://www.serif.com/"
exclude-result-prefixes="svg serif xlink" >
<xsl:output method="xml" indent="yes" omit-xml-declaration="yes" exclude-result-prefixes="svg serif xlink"/>
<xsl:strip-space elements="*"/>
<xsl:template match="@xlink:noNamespaceSchemaLocation"/>
<xsl:template match="@serif:noNamespaceSchemaLocation"/>
<xsl:template match="@svg:noNamespaceSchemaLocation"/>
<xsl:template match="tspan" priority="1000"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="@serif:id"/>
<xsl:template match="@gradientUnits"/>
<xsl:template match="@gradientTransform"/>
<xsl:template match="@id"/>
<xsl:template match="*" priority="100">
<xsl:element name="svg:{name()}" namespace="{namespace-uri()}">
<xsl:copy-of select="namespace::*[not(. = 'http://www.w3.org/1999/xlink/')]" />
<xsl:variable name="localName" select="local-name()"/>
<!-- keep @id for linearGradient -->
<xsl:if test="$localName = 'linearGradient'">
<xsl:attribute name="id"><xsl:value-of select="@id"/></xsl:attribute>
</xsl:if>
<xsl:apply-templates select="node()|@*"/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
The if-query is certainly messy. But I couldn't do it any other way. Templates for concrete elements don't seem to do anything at all.
Can anyone give me tips on what I'm doing wrong?
Thanks a lot
Regards
Apollo
-
- Posts: 9421
- Joined: Fri Jul 09, 2004 5:18 pm
Re: Convert svg to embedded svg with XSLT
Hi Apollo,
So about your problems:
because it is not namespace wellformed, the svg prefix does not bind to a namespace.
So what you want cannot be achieved only with XSLT, you would need an extra regular expression find replace afterwards to remove the namespace declaration.
The "tspan" element in the original SVG is in the namespace "http://www.w3.org/2000/svg".
The XPath "tspan" matches an element with local name "tspan" but in an empty namespace (or no namespace as we call this).
If you add an extra "xmlns="http://www.w3.org/2000/svg"" definition on the "xsl:stylesheet" root element, all Xpaths which do not specify a prefix will match elements in the "xmlns="http://www.w3.org/2000/svg"" namespace.
Or you can also do this:
to match tspan in any namespace, or this:
I hope this helps.
Regards,
Radu
So about your problems:
An XSLT only generates namespace wellformed XML documents, so you cannot generate this with an XSLT:namespace in root element
Code: Select all
<svg:svg></svg:svg>
So what you want cannot be achieved only with XSLT, you would need an extra regular expression find replace afterwards to remove the namespace declaration.
So you got this template:and tspan are not removed
Code: Select all
<xsl:template match="tspan" priority="1000"/>
The XPath "tspan" matches an element with local name "tspan" but in an empty namespace (or no namespace as we call this).
If you add an extra "xmlns="http://www.w3.org/2000/svg"" definition on the "xsl:stylesheet" root element, all Xpaths which do not specify a prefix will match elements in the "xmlns="http://www.w3.org/2000/svg"" namespace.
Or you can also do this:
Code: Select all
<xsl:template match="*:tspan"/>
Code: Select all
<xsl:template match="s:tspan" xmlns:s="http://www.w3.org/2000/svg"/>
Regards,
Radu
Radu Coravu
<oXygen/> XML Editor
http://www.oxygenxml.com
<oXygen/> XML Editor
http://www.oxygenxml.com
-
- Posts: 9421
- Joined: Fri Jul 09, 2004 5:18 pm
Re: Convert svg to embedded svg with XSLT
I forgot,
About your original need, why don't you just refer to the SVG images using the DITA "image" element?
If you want the SVG to be embedded in the result HTML output (maybe it contains animation for example) there is also this older publishing plugin which does this dynamically at publishing time:
https://github.com/oxygenxml/oxygen-embed-images
Regards,
Radu
About your original need, why don't you just refer to the SVG images using the DITA "image" element?
If you want the SVG to be embedded in the result HTML output (maybe it contains animation for example) there is also this older publishing plugin which does this dynamically at publishing time:
https://github.com/oxygenxml/oxygen-embed-images
Regards,
Radu
Radu Coravu
<oXygen/> XML Editor
http://www.oxygenxml.com
<oXygen/> XML Editor
http://www.oxygenxml.com
-
- Posts: 8
- Joined: Mon Nov 26, 2018 12:56 am
Re: Convert svg to embedded svg with XSLT
Hi Radu,
thank you very much for your quick and detailed answer.
I use these embedded svg when it comes to illustrations with text. It's easier for the translation process. These texts are then part of the DITA file. External svg files would be much more complicated for this.
Of course, this also has limitations because there are no multi-line texts in svg. But it is sufficient for simple screen images or flowcharts.
I'll report back when I've tried everything.
Thanks
Regards
Apollo
P.S. I'm looking forward seeing you live on stage with your hat on again.
thank you very much for your quick and detailed answer.
I use these embedded svg when it comes to illustrations with text. It's easier for the translation process. These texts are then part of the DITA file. External svg files would be much more complicated for this.
Of course, this also has limitations because there are no multi-line texts in svg. But it is sufficient for simple screen images or flowcharts.
I'll report back when I've tried everything.
Thanks
Regards
Apollo
P.S. I'm looking forward seeing you live on stage with your hat on again.

Radu wrote: ↑Thu Nov 18, 2021 11:43 am I forgot,
About your original need, why don't you just refer to the SVG images using the DITA "image" element?
If you want the SVG to be embedded in the result HTML output (maybe it contains animation for example) there is also this older publishing plugin which does this dynamically at publishing time:
https://github.com/oxygenxml/oxygen-embed-images
Regards,
Radu
Jump to
- Oxygen XML Editor/Author/Developer
- ↳ Feature Request
- ↳ Common Problems
- ↳ DITA (Editing and Publishing DITA Content)
- ↳ SDK-API, Frameworks - Document Types
- ↳ DocBook
- ↳ TEI
- ↳ XHTML
- ↳ Other Issues
- Oxygen XML Web Author
- ↳ Feature Request
- ↳ Common Problems
- Oxygen Content Fusion
- ↳ Feature Request
- ↳ Common Problems
- Oxygen JSON Editor
- ↳ Feature Request
- ↳ Common Problems
- Oxygen PDF Chemistry
- ↳ Feature Request
- ↳ Common Problems
- Oxygen Feedback
- ↳ Feature Request
- ↳ Common Problems
- Oxygen XML WebHelp
- ↳ Feature Request
- ↳ Common Problems
- XML
- ↳ General XML Questions
- ↳ XSLT and FOP
- ↳ XML Schemas
- ↳ XQuery
- NVDL
- ↳ General NVDL Issues
- ↳ oNVDL Related Issues
- XML Services Market
- ↳ Offer a Service