Чтобы достичь этого, используя только один оператор xsl: foreach, попробуйте следующее:
<xsl:for-each select="$all_alerts[g:problem!='normal_service'][g:service='bus']">
<xsl:sort select="not(number(g:line))"/>
<xsl:sort select="number(g:line)" data-type="number"/>
<xsl:sort select="g:line"/>
<xsl:value-of select="normalize-space(g:line)" /><xsl:text/>
<xsl:if test="position()!=last()"><xsl:text>, </xsl:text></xsl:if>
</xsl:for-each>
Первый xsl: sort сортирует, является ли строка числом или нет. not () возвращает false, если строка является числом, и true, если это не так. ложь сортируется до истины, и поэтому числа выходят первыми. Если вы пропустите этот вид, буквы появятся первыми.
Следующее xsl: sort сортирует по номерам, поэтому сортирует числа правильно, но не влияет на буквы (которые все возвращают NaN, когда применено число ()).
Финальный xsl: sort отсортирует буквы по алфавиту.