XSLT: поиск последнего вхождения в строке - PullRequest
8 голосов
/ 29 июня 2010

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

ABC_12345_Q-10

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

ABC12345

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

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

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

Ответы [ 4 ]

11 голосов
/ 29 июня 2010

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

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

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
5 голосов
/ 12 декабря 2012

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

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

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

2 голосов
/ 29 июня 2010
concat(
    substring-before($s, '_'),
    substring-before(substring-after($s, '_'), '_')
)

В качестве альтернативы:

string-join(tokenize($s, '_')[position() <= 2], '')
0 голосов
/ 11 августа 2017

Обобщенный -

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

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

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

...