2010-04-15 12 views
10

Estoy tratando de formatear cadenas en XSLT que deben estar en caso pascal para ser usadas apropiadamente para la aplicación con la que estoy trabajando.¿Cómo formatear una cadena al caso de Pascal en XSLT?

Por ejemplo:

this_text se convertiría en estetexto
this_long_text se convertiría en ThisLongText

¿Es posible configurar también este hasta donde puedo enviar una entrada al formato entonces no tengo que volver a crear el formato varias veces?

+0

Buena pregunta (+1). Consulte mi respuesta para obtener una solución XSLT completa :) –

+0

El proceso ** reverse ** también está disponible. Ver mi respuesta a continuación. ;-) –

Respuesta

8

Esta transformación:

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
<xsl:output omit-xml-declaration="yes" indent="yes"/> 

<xsl:variable name="vLower" select= 
    "'abcdefghijklmnopqrstuvwxyz'"/> 

<xsl:variable name="vUpper" select= 
    "'ABCDEFGHIJKLMNOPQRSTUVWXYZ'"/> 

<xsl:template match="node()|@*"> 
    <xsl:copy> 
    <xsl:apply-templates select="node()|@*"/> 
    </xsl:copy> 
</xsl:template> 

<xsl:template match="text()"> 
    <xsl:call-template name="Pascalize"> 
    <xsl:with-param name="pText" select="concat(., '_')"/> 
    </xsl:call-template> 
</xsl:template> 

<xsl:template name="Pascalize"> 
    <xsl:param name="pText"/> 

    <xsl:if test="$pText"> 
    <xsl:value-of select= 
    "translate(substring($pText,1,1), $vLower, $vUpper)"/> 

    <xsl:value-of select="substring-before(substring($pText,2), '_')"/> 

    <xsl:call-template name="Pascalize"> 
    <xsl:with-param name="pText" 
     select="substring-after(substring($pText,2), '_')"/> 
    </xsl:call-template> 
    </xsl:if> 
</xsl:template> 
</xsl:stylesheet> 

cuando se aplica en este documento XML:

<t> 
    <a>this_text</a> 
    <b>this_long_text</b> 
</t> 

produce el resultado deseado:

<t> 
    <a>ThisText</a> 
    <b>ThisLongText</b> 
</t> 

Por cierto, esto es camelCase y esto es PascalCase

+0

+1 Impresionante - muy bien hecho! –

+0

Gracias por la respuesta rápida, trabajando en implementarlo ahora. Estoy de acuerdo con Andrew, ¡muy bien hecho! – OpenDataAlex

+0

Pregunta de seguimiento rápido: la transformación que estoy creando consiste en convertir un archivo XML en un archivo YAML. Esto parece afectar todo el texto y no solo los encabezados específicos. ¿Hay alguna manera de especificar qué texto quiero ejecutar a través de la plantilla Pascalize? Gracias de nuevo por guiarme por el camino correcto. – OpenDataAlex

0

Gracias a Dimitre, yo era capaz de conseguir la mayor parte del camino. Cuando ejecuté mis cadenas a través de la plantilla Pascalize, el bit después del último '_' fue cortado. Probablemente hay una forma más limpia de hacerlo, pero aquí está el código que utilicé:

<xsl:template name="Pascalize"> 
    <xsl:param name="pText"/> 

    <xsl:if test="$pText"> 
     <xsl:value-of select="translate(substring($pText,1,1), $vLower, $vUpper)"/> 

     <xsl:value-of select="substring-before(substring($pText,2), '_')"/> 

     <xsl:call-template name="Pascalize"> 
      <xsl:with-param name="pText" select="substring-after(substring($pText,2), '_')"/> 
     </xsl:call-template> 

     <xsl:call-template name="GrabLastPart"> 
      <xsl:with-param name="pText" select="$pText"/> 
     </xsl:call-template> 
    </xsl:if> 
</xsl:template> 

<xsl:template name="GrabLastPart"> 
    <xsl:param name="pText"/> 

    <xsl:choose> 
     <xsl:when test="contains($pText, '_')"> 
      <xsl:call-template name="GrabLastPart"> 
       <xsl:with-param name="pText" expr="substring-after($pText, '_')"/> 
      </xsl:call-template> 
     </xsl:when> 
     <xsl:otherwise> 
      <xsl:value-of select="substring($pText, 2)"/> 
     </xsl:otherwise> 
    </xsl:choose> 
</xsl:template> 
4

Esta versión funcionó para mí. Agregué una opción que arroja "el resto" de la cadena cuando ya no hay barras debajo de la barra.

<xsl:variable name="vLower" select="'abcdefghijklmnopqrstuvwxyz'"/> 
<xsl:variable name="vUpper" select="'ABCDEFGHIJKLMNOPQRSTUVWXYZ'"/> 

<xsl:template name="Pascalize"> 
    <xsl:param name="pText" /> 
    <xsl:if test="$pText"> 
     <xsl:value-of select="translate(substring($pText,1,1), $vLower, $vUpper)" /> 
     <xsl:choose> 
      <xsl:when test="contains($pText, '_')"> 
       <xsl:value-of select="substring-before(substring($pText,2), '_')" /> 
      </xsl:when> 
      <xsl:otherwise> 
       <xsl:value-of select="substring($pText,2)" /> 
      </xsl:otherwise> 
     </xsl:choose> 
     <xsl:call-template name="Pascalize"> 
      <xsl:with-param name="pText" select="substring-after(substring($pText,2), '_')" /> 
     </xsl:call-template> 
    </xsl:if> 
</xsl:template> 

Además, en caso de que alguien viene aquí buscando el proceso inverso (que me pasó a requerir también hoy y no pude encontrar un solo ejemplo de en cualquier lugar) ...

<xsl:variable name="vLower" select="'abcdefghijklmnopqrstuvwxyz'"/> 
<xsl:variable name="vUpper" select="'ABCDEFGHIJKLMNOPQRSTUVWXYZ'"/> 

<xsl:template name="TitleCase"> 
    <xsl:param name="pText" /> 
    <xsl:call-template name="TitleCase_recurse"> 
     <xsl:with-param name="pText" select="concat(translate(substring($pText,1,1), $vLower, $vUpper), substring($pText,2))" /> 
    </xsl:call-template> 
</xsl:template> 

<xsl:template name="TitleCase_recurse"> 
    <xsl:param name="pText" /> 
    <xsl:if test="string-length($pText) &gt; 1"> 
     <xsl:if test="not(substring($pText,1,1) = ' ' and substring($pText,1,1) = ' ')"> 
      <xsl:value-of select="substring($pText,1,1)" /> 
     </xsl:if> 
     <xsl:if test="translate(substring($pText,1,1), $vLower, $vUpper) != substring($pText,1,1)"> 
      <xsl:if test="translate(substring($pText,2,1), $vLower, $vUpper) = substring($pText,2,1)"> 
       <xsl:text> </xsl:text> 
      </xsl:if> 
     </xsl:if> 
     <xsl:call-template name="TitleCase_recurse"> 
      <xsl:with-param name="pText" select="substring($pText,2)" /> 
     </xsl:call-template> 
    </xsl:if> 
    <xsl:if test="string-length($pText) = 1"> 
     <xsl:value-of select="$pText" /> 
    </xsl:if> 
</xsl:template> 

Me encanta cuando mi cerebro inconsciente muestra una respuesta unas horas después de que me haya rendido por completo conscientemente. ;-)

+0

Bien hecho. Siempre es un proceso de aprendizaje con estas cosas, je. – OpenDataAlex

1

yo estaba tratando de lograr el "pascalizing" con la siguiente función XLST llamada:

<xsl:value-of select="fn:replace(@name,'_(\w{1})','\U$1')"/> 

Desafortunadamente el procesador lanza el mensaje de error "cadena de reemplazo no válida en replace(): \ personaje debe ser seguido por \ o $

el problema es el modificador \ U que se supone que hace la conversión en mayúsculas del patrón coincidente.Si lo cambio a

<xsl:value-of select="fn:replace(@name,'_(\w{1})','\\U$1')"/> 

la cadena de salida contiene la secuencia '\ T' porque ahora se esacped - pero no quiero escapar de ella, quiero que seas eficaz ;-). Hice la prueba

<xsl:value-of select="fn:replace(@name,'_(\w{1})','$1')"/> 

(sin necesidad de convertir el partido en mayúsculas) y que funciona bien. Pero, por supuesto, no hace uppercasing, simplemente elimina guiones bajos y reemplaza la letra después del guión bajo por sí mismo en lugar de capitalizarlo. ¿Estoy haciendo algo mal aquí o el modificador \ U simplemente no es compatible con la implementación de expresiones regulares de mi procesador XSLT?

+0

No soy un experto en expresiones regulares de ninguna manera, pero no creo que \ U sea compatible. – OpenDataAlex

6

Aquí, dos años después del hecho, es una solución XSLT 2.0:

<xsl:function name="fn:pascal-case"> 
    <xsl:param name="string"/> 
    <xsl:value-of select="string-join(for $s in tokenize($string,'\W+') return concat(upper-case(substring($s,1,1)),substring($s,2)),'')"/> 
</xsl:function> 

Será pascalize bien 'this_long_text' o 'esto-largo texto' a 'ThisLongText' porque se rompe en cualquier país que no - Personajes de palabras

En los sabores de expresiones regulares que estoy familiarizado con (perl, pcre, etc.), un guión bajo se considera parte de la clase de caracteres '\ w' (por lo tanto, no forma parte de \ W), pero para XSLT 2.0 tipos de datos se utilizan (http://www.w3.org/TR/xmlschema-2/) y '\ w' se define como:

[#x0000-#x10FFFF]-[\p{P}\p{Z}\p{C}] (all characters except the set of "punctuation", "separator" and "other" characters) 

así 'W \' incluye un carácter de subrayado.

Cuestiones relacionadas