XSL conversion produces different results when exchanging two identical strings

I am trying to merge into an svg file in one. I have two files: bg.svg:

<?xml version="1.0" encoding="UTF-8" standalone="no"?> <svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="500" height="500" xml:space="preserve"> <g> <circle cy="250px" cx="250px" r="200" style="fill:black"></circle> <circle cy="250px" cx="250px" r="195" style="fill:white"></circle> </g> </svg> 

and "arrow.svg":

 <?xml version="1.0" encoding="UTF-8" standalone="no"?> <svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="500" height="500" id="arrow" xml:space="preserve"> <g id="g10"> <path d="M 250 245 L 250 255 L 400 255 L 400 265 L 415 250 L 400 235 L 400 245 L 250 245 " style="fill:red;stroke:#500;"></path> </g> </svg>. 

Then I try to combine it with the following XSL template:

 <?xml version="1.0" encoding="UTF-8" standalone="no"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:svg="http://www.w3.org/2000/svg"> <xsl:variable name="bg-doc" select="document('bg.svg')"/> <xsl:template match="/svg:svg"> <xsl:copy> <xsl:apply-templates select="./@*|./node()" /> <xsl:apply-templates select="$bg-doc/svg:svg/svg:g" /> </xsl:copy> </xsl:template> <xsl:template match="@*|node()"> <xsl:copy> <xsl:apply-templates select="@*|node()"/> </xsl:copy> </xsl:template> </xsl:stylesheet> 

... using this Java code:

 TransformerFactory factory = TransformerFactory.newInstance(); Transformer transformer = factory.newTransformer( new StreamSource( new File("merge.xsl" ) ) ); transformer.transform( new StreamSource( new File("arrow.svg") ), new StreamResult( new File("out.svg") ) ); 

This conversion has the correct result:

 <?xml version = '1.0' encoding = 'UTF-8'?> <svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="500" height="500" id="arrow" xml:space="preserve"> <g id="g10"> <path d="M 250 245 L 250 255 L 400 255 L 400 265 L 415 250 L 400 235 L 400 245 L 250 245 " style="fill:red;stroke:#500;"/> </g> <g> <circle cy="250px" cx="250px" r="200" style="fill:black"/> <circle cy="250px" cx="250px" r="195" style="fill:white"/> </g> </svg> 

But when I try to reorder the 11 and 12 lines of an XSL template:

 <?xml version="1.0" encoding="UTF-8" standalone="no"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:svg="http://www.w3.org/2000/svg"> <xsl:variable name="bg-doc" select="document('bg.svg')"/> <xsl:template match="/svg:svg"> <xsl:copy> <xsl:apply-templates select="$bg-doc/svg:svg/svg:g" /> <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> 

... the conversion returns weird (invalid) XML:

 <?xml version = '1.0' encoding = 'UTF-8'?> <svg xmlns="http://www.w3.org/2000/svg"> <g> <circle cy="250px" cx="250px" r="200" style="fill:black"/> <circle cy="250px" cx="250px" r="195" style="fill:white"/> </g> <svg version="1.1" width="500" height="500" id="arrow" xml:space="preserve"> <g id="g10"> <path d="M 250 245 L 250 255 L 400 255 L 400 265 L 415 250 L 400 235 L 400 245 L 250 245 " style="fill:red;stroke:#500;"/> </g> </svg> 

Any ideas why this might happen?

+4
source share
1 answer

But, when I try to reorder the 11 and 12 lines of an XSL template:

 <xsl:template match="/svg:svg"> <xsl:copy> <xsl:apply-templates select="$bg-doc/svg:svg/svg:g" /> <xsl:apply-templates select="./@*|./node()" /> </xsl:copy> </xsl:template> 
Conversion

returns strange (invalid) XML

This is exactly what you indicated when swapping two lines of code: first, the svg:g element is copied from one of the SVG documents, then only the attributes of the top element and the entire remaining SVG document are copied.

Solution :

 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:svg="http://www.w3.org/2000/svg"> <xsl:output omit-xml-declaration="yes" indent="yes"/> <xsl:strip-space elements="*"/> <xsl:variable name="bg-doc" select= "document('file:///c:/temp/delete/bg.svg')"/> <xsl:template match="/svg:svg"> <xsl:copy> <xsl:apply-templates select="@*" /> <xsl:apply-templates select="$bg-doc/svg:svg/svg:g" /> <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> 

When this conversion is applied to the provided XML document ( arrow.svg ):

 <?xml version="1.0" encoding="UTF-8" standalone="no"?> <svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="500" height="500" id="arrow" xml:space="preserve"> <g id="g10"> <path d="M 250 245 L 250 255 L 400 255 L 400 265 L 415 250 L 400 235 L 400 245 L 250 245 " style="fill:red;stroke:#500;"></path> </g> </svg> 

and the provided second document ( bg.svg ) in c:\temp\delete\ :

 <?xml version="1.0" encoding="UTF-8" standalone="no"?> <svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="500" height="500" xml:space="preserve"> <g> <circle cy="250px" cx="250px" r="200" style="fill:black"></circle> <circle cy="250px" cx="250px" r="195" style="fill:white"></circle> </g> </svg> 

now the correct result is created :

 <svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="500" height="500" id="arrow" xml:space="preserve"><g> <circle cy="250px" cx="250px" r="200" style="fill:black"/> <circle cy="250px" cx="250px" r="195" style="fill:white"/> </g> <g id="g10"> <path d="M 250 245 L 250 255 L 400 255 L 400 265 L 415 250 L 400 235 L 400 245 L 250 245 " style="fill:red;stroke:#500;"/> </g> </svg> 

The explanation . Copying element attributes should immediately follow the xsl:copy statement for that element. Placing it after copying other elements leads to the placement of these attributes on the last copied element, and not on the original owner of the attributes.

+2
source

Source: https://habr.com/ru/post/1388127/


All Articles