dbl
dbl

Reputation: 163

Write to multiple text files, grouped by attribute value using XSLT-2.0

Given XML like this:

<?xml version="1.0" encoding="UTF-8"?>
<tmx version="1.4">
  <header creationtool="ACME TM Editor">
    <prop type="x-acme-db-name">test_deu</prop>
  </header>
  <body>
    <tu srclang="en">
      <prop type="x-acme-source-ipath">English/GUID-asdf.xml</prop>
      <prop type="x-acme-target-ipath">German/GUID-qwer.xml</prop>
      <prop type="x-acme-tm-uda-SID">Index</prop>
      <tuv xml:lang="en">
        <seg>text:editing</seg>
      </tuv>
      <tuv xml:lang="de">
        <seg>Text:bearbeiten</seg>
      </tuv>
    </tu>
    <tu srclang="en">
      <prop type="x-acme-source-ipath">English/GUID-lkjh.xml</prop>
      <prop type="x-acme-target-ipath">German/GUID-poiu.xml</prop>
      <prop type="x-acme-tm-uda-SID">Index</prop>
      <tuv xml:lang="en">
        <seg>text:finding</seg>
      </tuv>
      <tuv xml:lang="de">
        <seg>Text:suchen</seg>
      </tuv>
    </tu>
    <tu srclang="en">
      <prop type="x-acme-source-ipath">English/GUID-zxcv.xml</prop>
      <prop type="x-acme-target-ipath">German/GUID-vbnm.xml</prop>
      <prop type="x-acme-tm-uda-SID">Index</prop>
      <tuv xml:lang="en">
        <seg>text:replacing</seg>
      </tuv>
      <tuv xml:lang="de">
        <seg>Text:ersetzen</seg>
      </tuv>
    </tu>
  </body>
</tmx>

I'm trying to generate one file per xml:lang (2 in this case), where each file contains the text for the appropriate lang.

I started with the code below, but I see the variable is being set to all of the lang values at once ("en de en de en de"). Any help on how to fix this to achieve the desired output would be greatly appreciated.

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
    <xsl:output method="text" encoding="UTF-8" />
    <xsl:template match="/tmx/body">
        <xsl:for-each-group select="tu/tuv/seg" group-by="//@xml:lang">
            <xsl:variable name="lg" select="//@xml:lang" />
            <xsl:result-document href="foo_{$lg}.txt" method="text">
                <xsl:copy-of select="current-group()" />
            </xsl:result-document>
        </xsl:for-each-group>
    </xsl:template>
</xsl:stylesheet>

Upvotes: 0

Views: 225

Answers (2)

dbl
dbl

Reputation: 163

Solution, thanks to Marcus & Martin:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
    <xsl:output method="text" encoding="UTF-8" />
    <xsl:template match="/tmx/body">
        <xsl:for-each-group select="tu/tuv/seg" group-by="../@xml:lang">
            <xsl:variable name="lg" select="../@xml:lang" />
            <xsl:result-document href="foo_{$lg}.txt" method="text">
                <xsl:value-of select="current-group()" separator="&#10;" />
            </xsl:result-document>
        </xsl:for-each-group>
    </xsl:template>
</xsl:stylesheet>

Upvotes: 0

Marcus Rickert
Marcus Rickert

Reputation: 4238

Using the absolute path //@xml:lang as you did will return the attributes of a node set consisting of all languages found in your file.

The group-by expression is usually given as relative path to the expression selecting the group. In your case this should simply be ../@xml_lang since the grouping criterion resides in the parent node. This will give you exactly one language per <seg>.

Upvotes: 1

Related Questions