Ali Soltani
Ali Soltani

Reputation: 9927

Split name of XML node by capital letter in xslt

I have a XML like this:

<process id="Process_1">
  <exclusiveGateway id="ExclusiveGateway_03b639w" />
  <startEvent id="StartEvent_0nmzsw0" />
  <sendTask id="Task_13s9uob"/>
  <userTask id="Task_1v0riz3" />
</process>

I need to convert it to this with xslt:

<process id="Process_1">
  <Gateway type="exclusive" id="ExclusiveGateway_03b639w" />
  <Event type="start" id="StartEvent_0nmzsw0" />
  <Task type="send" id="Task_13s9uob"/>
  <Task type="user" id="Task_1v0riz3" />
</process>

I think I can use tokenize function for this but I do not know how to separate tokens.

It would be very helpful if someone could explain solution for this problem.

Thanks.

Upvotes: 1

Views: 510

Answers (2)

michael.hor257k
michael.hor257k

Reputation: 116993

To do this in XSLT 1.0, try something along the lines of:

XSLT 1.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>

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

<xsl:template match="/process/*">
    <xsl:variable name="split" select="string-length(substring-before(translate(name(), 'BCDEFGHIJKLMNOPQRSTUVWXYZ', 'AAAAAAAAAAAAAAAAAAAAAAAAA'), 'A'))" />
    <xsl:element name="{substring(name(), $split + 1)}">
        <xsl:attribute name="type">
            <xsl:value-of select="substring(name(), 1, $split)"/>
        </xsl:attribute>
        <xsl:apply-templates select="@* | node()"/>
    </xsl:element>
</xsl:template>

</xsl:stylesheet>

Note that this assumes that all (and only) children of the root process element need to be processed as shown.


P.S. If you know the structure of the input XML, it would be more robust to transform the individual elements explicitly, e.g.:

<xsl:template match="exclusiveGateway">
     <Gateway type="exclusive">
        <xsl:apply-templates select="@* | node()"/>
    </Gateway>
</xsl:template>

Upvotes: 2

Martin Honnen
Martin Honnen

Reputation: 167571

Assuming the use of an XSLT 2.0 processor like Saxon 9 you can use

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="xs"
    version="2.0">

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

    <xsl:template match="*[matches(local-name(), '^\p{Ll}+\p{Lu}')]">
        <xsl:element name="{replace(local-name(), '^\p{Ll}+', '')}">
            <xsl:attribute name="type" select="replace(local-name(), '\p{Lu}.*', '')"/>
            <xsl:apply-templates select="@* | node()"/>
        </xsl:element>
    </xsl:template>
</xsl:stylesheet>

Online at http://xsltransform.net/jz1PuNM.

Upvotes: 2

Related Questions