3

I am using XSLT (2.0) as a java code generator. At the moment I have a XML which describes a database table and I want to generate the entity class for it.

The column names of the table are always lowercase with _ between the words.
Example: bat_valid_from
I want to rename it in the Java class to camelcase with first letter lowercase
Example: batValidFrom

Because I need this quiet often in my codeGen I like to have a function for it. But I only could achieve this with two sub functions.

<xsl:function name="local:VarName">
    <xsl:param name="columnName"/>
    <xsl:value-of select="lower-case(substring($columnName,1,1))"/>
    <xsl:value-of select="substring(local:VarName_sub($columnName),2)"/>
</xsl:function>
<xsl:function name="local:VarName_sub">
    <xsl:param name="columnName"/>
    <xsl:value-of select="local:VarName_sub_sub($columnName)"/>
</xsl:function>
<xsl:function name="local:VarName_sub_sub">
    <xsl:param name="columnName"/>
    <xsl:for-each select="tokenize($columnName, '_')">
        <xsl:value-of select="upper-case(substring(.,1,1))"/>
        <xsl:value-of select="substring(.,2)"/>
    </xsl:for-each>
</xsl:function>

Maybe someone has an idea to simplify this?
Without the sub functions I get the following error:
A sequence of more than one item is not allowed as the first argument of fn:substring()

PS: I haven't posted the whole code to shorten the question

Jason Aller
  • 3,541
  • 28
  • 38
  • 38
Momo
  • 456
  • 5
  • 22

2 Answers2

4

XSLT/XPath 2.0 has supports for expressions. You could do this:

string-join(
  for $part in tokenize($input, '_')
  return concat(
    upper-case(substring($part, 1, 1)),
    substring($part, 2)
  )
, '')

with $input set to 'bat_valid_from', this expression would produce 'BatValidFrom'.

I'm leaving lower-casing (or not upper-casing) the initial letter as an exercise.

Tomalak
  • 332,285
  • 67
  • 532
  • 628
  • thanks for your answer, i never heard from FLWOR before. To you need extra Tags to define them? Or simply write this in the XSLT-Code? Because when I use this code it simply prints it out as a text. Or ist there a FLWOR processor I need? – Momo Oct 13 '18 at 11:23
  • This is a regular expression in XPath 2.0. You can use it anywhere where XPath expressions are allowed in XSLT. I gave the name primarily so you know what to search for online. – Tomalak Oct 13 '18 at 11:25
  • Ahh okay so its an XQuery, not an XPath. Thank you now I understand. – Momo Oct 13 '18 at 11:31
  • 1
    It's XPath. It's also XPath when it is being used in XQuery, but in this case it's XPath being used in XSLT. – Tomalak Oct 13 '18 at 11:33
  • w3schools says somethin different, XPath is only to find nodes in XML . XQuery extands XPath with functions like FLWOR. Already discussed here https://stackoverflow.com/questions/924551/difference-between-xpath-xquery-and-xpointer – Momo Oct 13 '18 at 11:39
  • 1
    See the second answer in that thread. The concepts overlap. XSLT 2.0 does not support XQuery, it supports XPath 2.0. And XPath 2.0 supports [`for` expressions](https://www.w3.org/TR/xpath20/#id-for-expressions), which themselves are a subset of the full FLWOR expressions in XQuery. – Tomalak Oct 13 '18 at 11:46
  • For example, XQuery supports `for $item at $index in $sequence`, XPath 2.0 does not support `at`. – Tomalak Oct 13 '18 at 11:48
  • The Second answer says: XPath is intentionally limited to reading existing nodes. – Momo Oct 13 '18 at 11:51
  • see w3school maybe you believe them -> https://www.w3schools.com/xml/xquery_flwor.asp its under xquery not xpath – Momo Oct 13 '18 at 11:51
  • 1
    I do not consider w3schools credible. But that's besides the point. I gave the link to the XPath 2.0 specification. If you read anything, read that. – Tomalak Oct 13 '18 at 11:53
  • FLWOR ist not mentioned in your link, but you find it also on w3.org under xquery => https://www.w3.org/TR/xquery-30/#id-atomization – Momo Oct 13 '18 at 11:56
  • But dont let us discuss this here, you helped me. Thank you for that – Momo Oct 13 '18 at 11:57
  • 1
    That's why I said "it's XPath, not XQuery" and linked the part of the specification with the title `for` expressions. But I understand that it wasn't proper to call them FLWOR. I'm changing the answer text. – Tomalak Oct 13 '18 at 11:59
2

With the hint from Tomalak i was able to make all in one function.
Maybe not light weighted but works like a charm.

<xsl:function name="local:VarName">
    <xsl:param name="columnName"/>
    <xsl:value-of select="
        concat(
            lower-case(substring($columnName, 1, 1)),
            substring(string-join(for $word in tokenize($columnName, '_')
                                      return concat(
                                          upper-case(substring($word, 1, 1)),
                                          substring($word, 2)), '')
                     , 2))" />
</xsl:function>
Momo
  • 456
  • 5
  • 22
  • Tip: Save the intermediary result into an`` so you don't have to calculate it twice. Alternatively you could combine `substring-before()` and `substring-after()` to handle the bit before the first `_` differently. – Tomalak Oct 13 '18 at 12:42