6

I want to translate a given XML file (it is a RelaxNG grammar) to other languages via XSLT. Suppose the XML file is:

<?xml version="1.0" encoding="UTF-8"?>
<grammar>
  <element name="table" />
  <element name="chair" />
</grammar>

Now I was thinking of having an XSLT stylesheet with the information like

en=table, de=Tisch, fr=table
en=chair, de=Stuhl, fr=chaise
...  (there will be many, many more entries)

But I could also put this information in to an external file (I am starting from scratch). Can you give me advice how to formulate an XSLT? I was thinking of using <xsl:key> for this but I never get the hang of keys in XSLT. The result should look like this, when I create the German translation:

<?xml version="1.0" encoding="UTF-8"?>
<grammar lang="de">
  <element name="Tisch" />
  <element name="Stuhl" />
</grammar>
Dimitre Novatchev
  • 240,661
  • 26
  • 293
  • 431
topskip
  • 16,207
  • 15
  • 67
  • 99

1 Answers1

6

This transformation:

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

 <xsl:param name="pFrom" select="'en'"/>
 <xsl:param name="pTo" select="'de'"/>

 <xsl:key name="kIdByLangVal" match="@dId"
  use="concat(../../@lang, '+', ../@value)"/>

 <xsl:key name="kValByLangId" match="@value"
  use="concat(../../@lang, '+', ../@dId)"/>

 <xsl:variable name="vDicts" select=
  "document('file:///c:/temp/delete/dicts.xml')"/>

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

 <xsl:template match="@name">
  <xsl:variable name="vCur" select="."/>

  <xsl:attribute name="name">
   <xsl:for-each select="$vDicts">
    <xsl:value-of select=
     "key('kValByLangId',
          concat($pTo, '+',
                key('kIdByLangVal',
                    concat($pFrom, '+', $vCur)
                   )
                 )
        )
     "/>
   </xsl:for-each>
  </xsl:attribute>
 </xsl:template>
</xsl:stylesheet>

when applied on the provided XML document:

<grammar>
    <element name="table" />
    <element name="chair" />
</grammar>

and having the file C:\temp\delete\dicts.xml as:

<dictionaries>
 <dictionary lang="en">
  <word dId="1" value="table"/>
  <word dId="2" value="chair"/>
 </dictionary>
 <dictionary lang="de">
  <word dId="1" value="Tisch"/>
  <word dId="2" value="Stuhl"/>
 </dictionary>
</dictionaries>

produces the wanted, correct result:

<grammar>
   <element name="Tisch"/>
   <element name="Stuhl"/>
</grammar>
Dimitre Novatchev
  • 240,661
  • 26
  • 293
  • 431
  • The way xsl stylesheets look always scare the wits out of me. ;) – DanMan Nov 25 '11 at 23:43
  • 2
    @DanMan: What scares *me* is the look of an imperative, spaghetti-like code :) – Dimitre Novatchev Nov 26 '11 at 00:02
  • First of all: thanks Dimitre, you always post great answers! Currently I am not too happy with the long dictionary (when I have 100 entries, it gets difficult to see what is the correct number). I should have thought about this in advance. I am currently playing with your solution and try to apply it to a dictionary with the following style: ``. – topskip Nov 26 '11 at 13:01
  • 1
    I have been playing with it for a while and came up with a different solution (inspired by yours, thanks again!). I have posted a follup-up question on how this could be improved: http://stackoverflow.com/questions/8278798/is-this-xslt-inefficient – topskip Nov 26 '11 at 13:47
  • @Patrick: You are welcome. I prefer the current (in my answer) structure of the dictionary, because it makes the different languages almost independent and we can split the huge dictionary easily into several dictionaries -- each for just one language. I'll have a look at your new question. – Dimitre Novatchev Nov 26 '11 at 15:45