XSLT: поиск последнего появления в строке

учитывая номер формы, как:

ABC_12345_Q-10

Я хочу закончить с:

ABC12345

поэтому мне нужно найти позицию второго подчеркивания

обратите внимание, что нет стандартного шаблона или длины для любого из "разделов" между подчеркиваниями (поэтому я не могу использовать подстроку, чтобы просто исключить последний раздел).

решения xPath 2.0 в порядке.

4 ответов


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

кроме того:

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

@Pavel_Minaev предоставил решения XPath 1.0 amd XPath 2.0, которые работают, если заранее известно, что число подчеркиваний равно 2.

вот решения для более сложной проблемы, где количество undrscores не известно статически (может быть любое количество):

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>

когда это преобразование применяется к любому XML-документу (не используется), желаемый, правильный результат получается:

ABC12345

более простое решение в XSLT 2.0:

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

С 'substring-before' вы получите все после на последние возникновение вашего разделителя (подчеркивание). Если вместо этого вы используете "substring-after", вы получите все до на последние появление ваших deliminator.


обобщенное -

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

идея состоит в том, чтобы получить индекс последнего вхождения, разделив строку.

индекс последнего вхождения = string-length ($string) - длина последней строки после split