The pattern you are looking for is a “modified identity transformation”. The basis of this approach is the identity transformation rule, the first rule of the template in the stylesheet below. Each rule then represents an exception from copy mode.
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="foo"/>
<xsl:template match="bar">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="bat">
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:attribute name="id">123</xsl:attribute>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
What suits me the least is the duplication of logic found in the last rule of the template. This is a lot of code for just adding a single attribute. And imagine if we need a bunch of them. Here is another approach that allows us to be more quickly accurate in what we want to redefine:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:apply-templates mode="add-atts" select="."/>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
<xsl:template mode="add-atts" match="*"/>
<xsl:template mode="add-atts" match="bat">
<xsl:attribute name="id">123</xsl:attribute>
</xsl:template>
</xsl:stylesheet>
, , , , , :
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template mode="add-atts" match="bat">
<xsl:attribute name="id">123</xsl:attribute>
</xsl:template>
<xsl:template mode="append" match="bat">
<new-element/>
</xsl:template>
<xsl:template mode="insert" match="foo">
<inserted/>
</xsl:template>
<xsl:template mode="before" match="bar | bat">
<before-bat-and-bar/>
</xsl:template>
<xsl:template mode="after" match="bat">
<after-bat/>
</xsl:template>
<xsl:template match="@* | node()">
<xsl:apply-templates mode="before" select="."/>
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:apply-templates mode="add-atts" select="."/>
<xsl:apply-templates mode="insert" select="."/>
<xsl:apply-templates/>
<xsl:apply-templates mode="append" select="."/>
</xsl:copy>
<xsl:apply-templates mode="after" select="."/>
</xsl:template>
<xsl:template mode="add-atts" match="*"/>
<xsl:template mode="insert" match="*"/>
<xsl:template mode="append" match="*"/>
<xsl:template mode="before" match="@* | node()"/>
<xsl:template mode="after" match="@* | node()"/>
</xsl:stylesheet>
XSLT 2.0 :
<xsl:template mode="add-atts
insert
append
before
after" match="@* | node()"/>
, - .