Split name of XML node by capital letter in xslt

2019-07-31 14:52发布

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.

标签: xml xslt
2条回答
家丑人穷心不美
2楼-- · 2019-07-31 15:43

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.

查看更多
Melony?
3楼-- · 2019-07-31 15:50

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>
查看更多
登录 后发表回答