Я пробую к строкам формата в XSLT, который должен быть в случае Паскаля, который будет использоваться соответственно для приложения, с которым я работаю.
Например:
this_text стал бы ThisText
this_long_text стал бы ThisLongText
Действительно ли возможно также настроить это, куда я могу отправить вход в формат, таким образом, я не должен воссоздавать формат многократно?
Это преобразование:
<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>
при применении к этому XML-документу:
<t>
<a>this_text</a>
<b>this_long_text</b>
</t>
дает желаемый результат:
<t>
<a>ThisText</a>
<b>ThisLongText</b>
</t>
Кстати, это camelCase, а это PascalCase
Благодаря Димитру мне удалось проделать большую часть пути. При прогоне моих строк через шаблон Pascalize бит после последнего '_' был обрезан. Вероятно, есть более чистый способ сделать это, но вот код, который я использовал:
<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>
У меня работала эта версия. Я добавил выбор, который выводит «остаток» строки, когда больше нет нижних полос.
<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>
Кроме того, на случай, если кто-нибудь придет сюда в поисках обратного процесса (который мне тоже понадобился сегодня, и я нигде не нашел ни одного примера ) ...
<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) > 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>
Мне нравится, когда мое подсознание выскакивает ответ через несколько часов после того, как я полностью сдался сознательно. ; -)
Я пытался добиться "паскализации" с помощью следующего вызова функции XLST:
<xsl:value-of select="fn:replace(@name,'_(\w{1})','\U$1')"/>
К сожалению, процессор выдает сообщение об ошибке "Недопустимая строка замены в replace (): После символа \ должен следовать \ или $ "
проблема в модификаторе \ U, который должен выполнять преобразование совпадающего шаблона в верхний регистр. Если я изменю его на
<xsl:value-of select="fn:replace(@name,'_(\w{1})','\\U$1')"/>
, выходная строка будет содержать последовательность '\ U 'потому что теперь он отключен - но я не хочу его избегать, я хочу, чтобы он был эффективным ;-). Я провел тест
<xsl:value-of select="fn:replace(@name,'_(\w{1})','$1')"/>
(без преобразования совпадения в верхний регистр), и это работает нормально. Но, конечно, это не использует верхний регистр, просто удаляет символы подчеркивания и заменяет букву после подчеркивания самостоятельно, вместо того, чтобы использовать заглавные буквы. Я делаю здесь что-то не так или модификатор \ U просто не поддерживается в реализации регулярного выражения в моем XSLT-процессоре?