Hayra
Hayra

Reputation: 466

XSLT 3.0 - replace number characters with number-string representations

I am trying to use xslt to create an xml data-set, and currently facing with problem that i am trying to set some invalid element names,3RD_RACK,3DATA_VIEW and what i've tried was to use :

<xsl:value-of select="translate(current()/@name), translate(current()/@name), 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_', ''), '_')"/>

which replaces 3RD_RACK -> _RD_RACK

and all other numbers in data-set like:

PROGRAMMDAUERPROGRAM1 -> PROGRAMMDAUERPROGRAM
ENERGY_CLASS_2010 -> ENERGY_CLASS__

What i came into my mind is to replace all numbers with their string representations to faciliate with xml validation such as :

1 -> one 2 -> two

So in the end my input becomes :

3RD_RACK -> threeRD_RACK, ENERGY_CLASS_twozeroonezero, PROGRAMMDAUERPROGRAMone

But, i couldn't achive my goal by trying:

    <xsl:variable name="MyMap" select="
            map { 
            '1' : 'one', 
            '2' : 'two',
            '3' : 'three',
            '4' : 'four',
            '5' : 'five',
            '6' : 'six', 
            '7' : 'seven',
            '8' : 'eight',
            '9' : 'nine'}">
        </xsl:variable>

<xsl:value-of select="$MyMap(current()/@name)"/>

returns only numbers, so can someone help me how i can translate only numbers occured in string ?

Thanks in advance for your answers.

Upvotes: 0

Views: 863

Answers (2)

michael.hor257k
michael.hor257k

Reputation: 116959

The easy solution would be to code the digits using other characters. Then you could do simply something like:

<xsl:element name="{translate(@name, '1234567890', 'αβγδεζηθικλμνξο')}">
    <xsl:apply-templates/>
</xsl:element>

This has the further advantage of being able to restore the original name (assuming it did not contain any of the characters used for the replacement). Using your method, it's impossible to tell if the original was "1d" or "oned".


Note also that your method could be implemented in the old-fashioned XSLT 1.0 way:

<xsl:variable name="name">
    <xsl:variable name="char1" select="substring(@name, 1, 1)"/>
    <xsl:choose>
        <xsl:when test="$char1='0'">zero</xsl:when>
        <xsl:when test="$char1='1'">one</xsl:when>
        <xsl:when test="$char1='2'">two</xsl:when>
        <xsl:when test="$char1='3'">three</xsl:when>
        <xsl:when test="$char1='4'">four</xsl:when>
        <xsl:when test="$char1='5'">five</xsl:when>
        <xsl:when test="$char1='6'">six</xsl:when>
        <xsl:when test="$char1='7'">seven</xsl:when>
        <xsl:when test="$char1='8'">eight</xsl:when>
        <xsl:when test="$char1='9'">nine</xsl:when>
        <xsl:otherwise>
            <xsl:value-of select="$char1"/>
        </xsl:otherwise>
    </xsl:choose>
    <xsl:value-of select="substring(@name, 2)"/>
</xsl:variable>
<xsl:element name="{$name}">
    <xsl:apply-templates/>
</xsl:element>

It doesn't seem much more verbose than XSLT 3.0.


Added:

I forgot to mention the most important thing: there are other ways a string can fail to conform to the XML name specification. If you cannot be sure that the provided name is a valid XML element name, then the most proper thing to do would be:

<elem name="{@name}">
   <xsl:apply-templates/>
</elem>

This is the simplest and at the same time, the safest, solution.

Upvotes: 1

Martin Honnen
Martin Honnen

Reputation: 167436

Here is an example that uses the analyze-string function from XPath 3 to replace any ASCII digit with the name from the map:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="#all"
    version="3.0">

  <xsl:output method="text"/>

  <xsl:variable name="MyMap" select="
            map { 
            '0' : 'zero',
            '1' : 'one', 
            '2' : 'two',
            '3' : 'three',
            '4' : 'four',
            '5' : 'five',
            '6' : 'six', 
            '7' : 'seven',
            '8' : 'eight',
            '9' : 'nine'}">
        </xsl:variable>

  <xsl:param name="names"
    as="xs:string*"
    select="'3RD_RACK', 'ENERGY_CLASS_2010', 'PROGRAMMDAUERPROGRAM1'"/>

  <xsl:variable name="converted-names"
    as="xs:string*"
    select="$names ! string-join(analyze-string(., '[0-9]')/*/(if (self::*:match) then $MyMap(.) else string()))"/>

  <xsl:template match="/">
      <xsl:value-of 
        select="$converted-names" separator="&#10;"/>
  </xsl:template>

</xsl:stylesheet>

Output:

threeRD_RACK
ENERGY_CLASS_twozeroonezero
PROGRAMMDAUERPROGRAMone

https://xsltfiddle.liberty-development.net/pPJ8LVj/2

Upvotes: 1

Related Questions