Преобразует первый символ каждого слова в верхний регистр

У меня есть строка, и мне нужно преобразовать первую букву каждого слова в верхний регистр и остальные в нижний регистр с помощью xsl, например,

входная строка= dInEsh sAchdeV kApil Muk

Требуемая Строка Вывода= Dinesh Sachdev Kapil Muk

хотя, я знаю, что должен использовать функцию translate для этой цели, но как я могу перевести первый устав каждого слова в верхний регистр и отдохнуть все в нижнем регистре с помощью XSLT 1.0

спасибо

7 ответов


следующее Не "приятно", и я уверен, что кто-то (в основном Дмитрий) может придумать что-то гораздо проще (особенно в XSLT 2.0)... но я ... --8-->проверили это, и это работает

<xsl:template name="CamelCase">
  <xsl:param name="text"/>
  <xsl:choose>
    <xsl:when test="contains($text,' ')">
      <xsl:call-template name="CamelCaseWord">
        <xsl:with-param name="text" select="substring-before($text,' ')"/>
      </xsl:call-template>
      <xsl:text> </xsl:text>
      <xsl:call-template name="CamelCase">
        <xsl:with-param name="text" select="substring-after($text,' ')"/>
      </xsl:call-template>
    </xsl:when>
    <xsl:otherwise>
      <xsl:call-template name="CamelCaseWord">
        <xsl:with-param name="text" select="$text"/>
      </xsl:call-template>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

<xsl:template name="CamelCaseWord">
  <xsl:param name="text"/>
  <xsl:value-of select="translate(substring($text,1,1),'abcdefghijklmnopqrstuvwxyz','ABCDEFGHIJKLMNOPQRSTUVWXYZ')" /><xsl:value-of select="translate(substring($text,2,string-length($text)-1),'ABCDEFGHIJKLMNOPQRSTUVWXYZ','abcdefghijklmnopqrstuvwxyz')" />
</xsl:template>

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

на CamelCaseWord шаблон просто переводит первый символ из Нижнего в верхний (при необходимости) и все остальные символы из верхнего в Нижний (при необходимости).

так это назвать вы бы...

<xsl:call-template name="CamelCase">
   <xsl:with-param name="text">dInEsh sAchdeV kApil Muk</xsl:with-param>
</xsl:call-template>

дополнительные:

я пропустил требование 1.0 в вопросе. Это будет работать только с версии 2.0.

оригинальный ответ ниже здесь.

Я считаю, что это сработало для меня некоторое время назад. Объявить функцию:

<xsl:function name="my:titleCase" as="xs:string">
    <xsl:param name="s" as="xs:string"/>
    <xsl:choose>
        <xsl:when test="lower-case($s)=('and','or')">
            <xsl:value-of select="lower-case($s)"/>
        </xsl:when>
        <xsl:when test="$s=upper-case($s)">
            <xsl:value-of select="$s"/>
        </xsl:when>
        <xsl:otherwise>
            <xsl:value-of select="concat(upper-case(substring($s, 1, 1)), lower-case(substring($s, 2)))"/>
        </xsl:otherwise>
    </xsl:choose>
</xsl:function>

и использовать его:

<xsl:sequence select="string-join(for $x in tokenize($text,'\s') return my:titleCase($x),' ')"/>

заслуга samjudson => http://p2p.wrox.com/xslt/80938-title-case-string.html


вот 8-летний FXSL 1.x (XSLT 1.0 libray полностью написан в XSLT 1.0) решение:

test-strSplit-to-Words10.язык xsl:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:ext="http://exslt.org/common"
>
   <xsl:import href="strSplitWordDel.xsl"/>

   <!-- To be applied on: test-strSplit-to-Words10.xml -->

   <xsl:output indent="yes" omit-xml-declaration="yes"/>
   <xsl:variable name="vLower" 
        select="'abcdefgijklmnopqrstuvwxyz'"/>
   <xsl:variable name="vUpper" 
        select="'ABCDEFGIJKLMNOPQRSTUVWXYZ'"/>

    <xsl:template match="/">
      <xsl:variable name="vwordNodes">
        <xsl:call-template name="str-split-word-del">
          <xsl:with-param name="pStr" select="/"/>
          <xsl:with-param name="pDelimiters" 
                          select="', .(&#9;&#10;&#13;'"/>
        </xsl:call-template>
      </xsl:variable>

      <xsl:apply-templates select="ext:node-set($vwordNodes)/*"/>
    </xsl:template>

    <xsl:template match="word">
       <xsl:choose>
         <xsl:when test="not(position() = last())">
           <xsl:value-of 
           select="translate(substring(.,1,1),$vLower,$vUpper)"/>
           <xsl:value-of select="substring(.,2)"/>
         </xsl:when>
         <xsl:otherwise>
           <xsl:value-of select="."/>
         </xsl:otherwise>
       </xsl:choose>
    </xsl:template>

    <xsl:template match="delim">
      <xsl:value-of select="."/>
    </xsl:template>
</xsl:stylesheet>

когда это преобразование применяется к следующему XML-документу (test-strSplit-to-Words10.XML-код):

<t>004.lightning crashes (live).mp3</t>

результат:

004.Lightning Crashes (Live).mp3

при применении к этому XML-документу (предоставленному вами образец):

dInEsh sAchdeV kApil Muk

результат:

DInEsh SAchdeV KApil Muk

С помощью всего лишь небольшой твик, мы получаем этот код:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:ext="http://exslt.org/common"
>
   <xsl:import href="strSplitWordDel.xsl"/>

   <!-- To be applied on: test-strSplit-to-Words10.xml -->

   <xsl:output indent="yes" omit-xml-declaration="yes"/>
   <xsl:variable name="vLower" 
        select="'abcdefgijklmnopqrstuvwxyz'"/>
   <xsl:variable name="vUpper" 
        select="'ABCDEFGIJKLMNOPQRSTUVWXYZ'"/>

    <xsl:template match="/">
      <xsl:variable name="vwordNodes">
        <xsl:call-template name="str-split-word-del">
          <xsl:with-param name="pStr" select="/"/>
          <xsl:with-param name="pDelimiters" 
                          select="', .(&#9;&#10;&#13;'"/>
        </xsl:call-template>
      </xsl:variable>

      <xsl:apply-templates select="ext:node-set($vwordNodes)/*"/>
    </xsl:template>

    <xsl:template match="word">
           <xsl:value-of 
           select="translate(substring(.,1,1),$vLower,$vUpper)"/>
           <xsl:value-of select="translate(substring(.,2), $vUpper, $vLower)"/>
    </xsl:template>

    <xsl:template match="delim">
      <xsl:value-of select="."/>
    </xsl:template>
</xsl:stylesheet>

который теперь производит желаемый результат:

Dinesh Sachdev Kapil Muk

объяснение:

на str-split-word-del шаблон FXSL может использоваться для токенизации с (возможно, более одного) разделителями, указанными в виде строки параметр.


вы также можете попробовать это:

http://www.xsltfunctions.com/xsl/functx_camel-case-to-words.html

 <xsl:function name="functx:camel-case-to-words" as="xs:string"
                  xmlns:functx="http://www.functx.com">
      <xsl:param name="arg" as="xs:string?"/>
      <xsl:param name="delim" as="xs:string"/>

      <xsl:sequence select="
       concat(substring($arg,1,1),
                 replace(substring($arg,2),'(\p{Lu})',
                            concat($delim, '')))
     "/>

</xsl:function>

и назад: http://www.xsltfunctions.com/xsl/functx_words-to-camel-case.html

<xsl:function name="functx:words-to-camel-case" as="xs:string"
              xmlns:functx="http://www.functx.com">
  <xsl:param name="arg" as="xs:string?"/>

  <xsl:sequence select="
     string-join((tokenize($arg,'\s+')[1],
       for $word in tokenize($arg,'\s+')[position() > 1]
       return functx:capitalize-first($word))
      ,'')
 "/>

</xsl:function>

вот еще одно короткое решение. Он использует чистый XSL-t 2.0. Я знаю, что у OP было требование для XSL-T 1.0, но поскольку эта страница занимает #1 в Google для "функции заголовка xsl-t" в 2015 году, это кажется более актуальным:

<xsl:function name="xx:fixCase">
    <xsl:param name="text" />
    <xsl:for-each select="tokenize($text,' ')">
        <xsl:value-of select="upper-case(substring(.,1,1))" />
        <xsl:value-of select="lower-case(substring(.,2))" />
        <xsl:if test="position() ne last()">
            <xsl:text> </xsl:text>
        </xsl:if>
    </xsl:for-each>
</xsl:function>

где ' xx ' - ваше собственное пространство имен.


эта же функция на XQUERY:

функция Xquery для случая верблюда.

declare function xf:toCamelCase($text as xs:string?) as xs:string{
    if(contains($text,' ')) then
        fn:concat(xf:CamelCaseWord(substring-before($text,' ')),' ', xf:toCamelCase(substring-after($text,' ')))
    else
        xf:CamelCaseWord($text)
};

declare function xf:CamelCaseWord($text as xs:string?) as xs:string{
    fn:concat( translate(substring($text,1,1),'abcdefghijklmnopqrstuvwxyz','ABCDEFGHIJKLMNOPQRSTUVWXYZ'), 
                translate(substring($text,2,string-length($text)-1),'ABCDEFGHIJKLMNOPQRSTUVWXYZ','abcdefghijklmnopqrstuvwxyz'))
};

очень короткое решение, использующее EXSLT split() функция:

<xsl:variable name='text' select='"dInEsh sAchdeV kApil Muk"' />
<xsl:variable name='lowers' select='"abcdefghijklmnopqrstuvwxyz"' />
<xsl:variable name='uppers' select='"ABCDEFGHIJKLMNOPQRSTUVWXYZ"' />

<xsl:template match="/">

    <xsl:for-each select='str:split($text, " ")'>
        <xsl:value-of select='concat(
            translate(substring(., 1, 1), $lowers, $uppers),
            translate(substring(., 2), $uppers, $lowers),
            " "
        )' />
    </xsl:for-each>
</xsl:template>

рабочая демо:http://www.xmlplayground.com/CNmKdF