Split name of XML node by capital letter in xslt

2019-07-31 15:22发布

问题:

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.

回答1:

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>


回答2:

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.



标签: xml xslt