Как отформатировать строку для случая Pascal в XSLT?
Я пытаюсь форматировать строки в XSLT, которые должны быть в папке для использования соответствующим образом для приложения, с которым я работаю.
Например:
this_text станет ThisText
this_long_text станет ThisLongText
Можно ли также установить это, где я могу отправить вход в формат, поэтому мне не нужно повторно создавать формат несколько раз?
Ответы
Ответ 1
Это преобразование:
<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
Ответ 2
Вот, через два года после этого, есть решение 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>
Он будет паскализовать либо "this_long_text", либо "this-long-text" в "ThisLongText", потому что он разбивается на любые символы, отличные от слов.
В ароматах регулярных выражений я больше всего знаком с (perl, pcre и т.д.), подчеркивание считается частью символьного класса '\ w' (поэтому не является частью \W), но для XSLT 2.0 типы данных XSD (http://www.w3.org/TR/xmlschema-2/) и '\ w' определяется как:
[#x0000-#x10FFFF]-[\p{P}\p{Z}\p{C}] (all characters except the set of "punctuation", "separator" and "other" characters)
поэтому '\ W' содержит символ подчеркивания.
Ответ 3
Эта версия работала для меня. Я добавил выбор, который выводит "остальную" строку, когда нет никаких нижних строчек.
<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>
Кроме того, в случае, если кто-то приходит сюда, ищет процесс reverse (который мне также понадобился сегодня и не смог найти ни одного примера в любом месте)...
<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>
Мне нравится, когда мой подсознательный мозг высказывает ответ через несколько часов после того, как я полностью сознательно отказался.; -)
Ответ 4
Я пытался выполнить "pascalizing" со следующим вызовом функции 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-процессора?
Ответ 5
Благодаря Димитрию, я смог получить большую часть пути. При запуске моих строк через шаблон 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>