2010-06-29 53 views
6

Dado un número de formulario como:XSLT: Encontrar la última ocurrencia de una cadena

ABC_12345_Q-10

Quiero terminar con:

ABC12345

así que tengo que encontrar la posición del segundo guión bajo

Tenga en cuenta que no hay un patrón estándar o longitud para ninguna de las "secciones" entre los guiones bajos (por lo que no puedo usar la subcadena para simplificar y eliminar la última sección).

xPath 2.0 soluciones ok

+0

¿Qué pasó con el primer guión de su muestra? – Lucero

+0

Buena pregunta (+1). Vea mi respuesta para las soluciones XPath 2.0 y XSLT 1.0 para el problema más general cuando la cantidad de guiones bajos no se conoce de antemano. :) –

Respuesta

2
concat(
    substring-before($s, '_'), 
    substring-before(substring-after($s, '_'), '_') 
) 

Alternativamente:

string-join(tokenize($s, '_')[position() <= 2], '') 
+0

Estos no funcionarán, porque darán ABC12345Q-10 –

+0

Ambos parecen funcionar bien. – johkar

11

@Pavel_Minaev ha proporcionado XPath 1.0 amd XPath 2,0 soluciones que funcionan si se sabe de antemano que el número de guiones es 2.

Aquí hay soluciones para el problema más difícil, donde el número de marcas no probadas no es estáticamente conocido (puede ser cualquier número):

XPath 2.0:

translate(substring($s, 
        1, 
        index-of(string-to-codepoints($s), 
          string-to-codepoints('_') 
          )[last()] -1 
        ), 
      '_', 
      '' 
     ) 

XSLT 1.0:

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
> 
<xsl:output method="text"/> 

    <xsl:variable name="s" select="'ABC_12345_Q-10'"/> 
    <xsl:template match="/"> 
    <xsl:call-template name="stripLast"> 
    <xsl:with-param name="pText" select="$s"/> 
    </xsl:call-template> 
    </xsl:template> 

    <xsl:template name="stripLast"> 
    <xsl:param name="pText"/> 
    <xsl:param name="pDelim" select="'_'"/> 

    <xsl:if test="contains($pText, $pDelim)"> 
     <xsl:value-of select="substring-before($pText, $pDelim)"/> 
     <xsl:call-template name="stripLast"> 
     <xsl:with-param name="pText" select= 
      "substring-after($pText, $pDelim)"/> 
     <xsl:with-param name="pDelim" select="$pDelim"/> 
     </xsl:call-template> 
    </xsl:if> 
    </xsl:template> 
</xsl:stylesheet> 

cuando esta transformación se aplica a cualquier documento XML (no se utiliza) , el resultado correcto y deseado se produce:

01 solución
4

más fácil en XSLT 2.0:

codepoints-to-string(reverse(string-to-codepoints(
    substring-before(
     codepoints-to-string(reverse(string-to-codepoints($s))), '_')))) 

Esto le dará todo antes de la última aparición de su delimitador (el subrayado).

0

generalizado uno -

substring($string,1, string-length($string)-string-length(str:split($string, '_')[count(str:split($string, '_'))])) 

idea es conseguir que el índice de la última aparición por la cadena división.

índice de la última aparición = cadena de longitud ($ cadena) - longitud de cadena después de la última división

+0

Una solución que depende de una función de extensión que solo admiten unos pocos procesadores es apenas una "generalizada". –

Cuestiones relacionadas