Reputation: 466
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
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
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=" "/>
</xsl:template>
</xsl:stylesheet>
Output:
threeRD_RACK
ENERGY_CLASS_twozeroonezero
PROGRAMMDAUERPROGRAMone
https://xsltfiddle.liberty-development.net/pPJ8LVj/2
Upvotes: 1