私が使用しているアプリケーションに適切に使用するために、パスカルケースにする必要がある XSLT で文字列をフォーマットしようとしています。
例えば:
this_textは ThisText になります this_long_textは
ThisLongTextになります
フォーマットに入力を送信できるように設定して、フォーマットを何度も再作成する必要がないようにすることはできますか?
私が使用しているアプリケーションに適切に使用するために、パスカルケースにする必要がある 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>
ところで、これはキャメルケースで、これはパスカルケースです
これは、事実から 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' にはアンダースコアが含まれます。
このバージョンは私にとってはうまくいきました。アンダーバーがなくなったときに文字列の「残り」を出力する選択を追加しました。
<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>
また、誰かが逆のプロセスを探してここに来た場合に備えて(今日もたまたま必要だったので、どこにも例が1つも見つかりませんでした)...
<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')"/>
(一致を大文字に変換せずに)そしてそれはうまくいきます。ただし、もちろん大文字は使用せず、アンダースコアを削除し、アンダースコアの後の文字を大文字にする代わりにそれ自体に置き換えます。ここで何か間違ったことをしているのですか、それとも XSLT プロセッサの正規表現実装で \U 修飾子がサポートされていないだけですか?
ディミトレのおかげで、ほとんどの場所にたどり着くことができました。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>