If you have access to commercial editions of Saxon 9.6 or 9.7 (for instance with oXygen or Stylus Studio) then you can do it in a generic way with XSLT 3.0 and a composite grouping key in group-ajacent:
Code:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:math="http://www.w3.org/2005/xpath-functions/math"
exclude-result-prefixes="xs math"
version="3.0">
<xsl:mode on-no-match="shallow-copy"/>
<xsl:template match="p">
<xsl:copy>
<xsl:for-each-group select="node()" group-adjacent="node-name(.), @class" composite="true">
<xsl:copy>
<xsl:copy-of select="@class"/>
<xsl:apply-templates select="current-group()/node()"/>
</xsl:copy>
</xsl:for-each-group>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
With XSLT 2.0 you could use a similar approach which concatenates the node-name() and the class attribute for the group-adjacent value, or as you have now posted some details you could use
Code:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:math="http://www.w3.org/2005/xpath-functions/math"
exclude-result-prefixes="xs math"
version="2.0">
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="p">
<xsl:copy>
<xsl:for-each-group select="node()" group-adjacent="self::span and @class = 'italic'">
<xsl:choose>
<xsl:when test="current-grouping-key()">
<xsl:copy>
<xsl:copy-of select="@class"/>
<xsl:apply-templates select="current-group()/node()"/>
</xsl:copy>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="current-group()"/>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each-group>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>