Self-closing <empty/> tags and an empty element with start and end <empty></empty> tags are semantically identical. Therefore, the XSLT processor can output depending on what it sees better.
You can try to trick the processor by adding empty content to the elements. In this case, this can be done by changing the identity template.
<xsl:variable name="empty" select="''"/> <xsl:template match="@* | node()"> <xsl:copy> <xsl:apply-templates select="@* | node()" /> <xsl:value-of select="$empty"/> </xsl:copy> </xsl:template>
Or you can restrict this to an empty element by keeping the original identification template and adding the following:
<xsl:template match="*[not(node())]"> <xsl:copy> <xsl:apply-templates select="@* | node()" /> <xsl:value-of select="$empty"/> </xsl:copy> </xsl:template>
Functionality is dependent on the XSLT processor.
Note. . A valid XML tool should not distinguish between self-closing tags or empty elements with start and end tags. Therefore, if this difference in syntax really causes problems, you should review what methods or tools you use or how you use them.
Update
Shit. For some reason, I continued to read your question in the opposite way (which probably means I should take a nap). So ... the code above is trying to convert self-closing tags to empty pairs, whereas you would like the opposite <tag></tag> β <tag/> . Sorry for the inconsistency, let me try again.
In the comment you said:
Before he was on a new line and indented to the same place as the opening tag.
From the point of view of the XML data model, this means that the node has only an empty space as child content. One way to avoid copying these text nodes is to provide them with an empty template. This can cause mixed content issues.
<xsl:template match="text()[normalize-space() = '']"/>
Another possible solution would be that when we come across empty elements, we create a new element with the same name and not copy it.
<xsl:template match="*[not(comment() | processing-instruction() | *)][normalize-space(text()) = '']"> <xsl:element name="{name()}" namespace="{namespace-uri()}"> <xsl:for-each select="@* | namespace::*"> <xsl:copy/> </xsl:for-each> </xsl:element> </xsl:template>
This template also copies the (unused) namespace definitions into empty elements, which actually seems completely unnecessary. <xsl:for-each> used instead of <xsl:apply-templates> only because template match does not allow the namespace axis to be used. <xsl:apply-templates select="@*"/> also works if you do not want to save additional namespace definitions.
But in the end, AFAIK are all just processor-specific workarounds. When an XSLT 1.0 processor creates an empty element, it is free to choose whether to use a self-closing tag or an empty pair. Someone please correct me if I am wrong.