0

I can't quite get my head around this.

So I have this external XML data file:

<?xml version="1.0" encoding="UTF-8"?>
<Translations xmlns="http://www.publictalksoftware.co.uk/msa">
  <en>
    <Chairman>Chairman</Chairman>
    <Conductor>Conductor</Conductor>
    <Hospitality>Hospitality</Hospitality>
    <Prayer>Prayer</Prayer>
    <PublicTalk>Public Talk</PublicTalk>
    <Reader>Reader</Reader>
    <ServiceTalk>Service Talk</ServiceTalk>
    <Speaker>Speaker</Speaker>
    <Theme>Theme</Theme>
    <WTStudy>Watchtower Study</WTStudy>
  </en>
</Translations>

It is referenced in my master XSL script like this:

<xsl:variable name="Translations" select="document('Workbook-S-140-Compact_2020_v2_Translations.XML')"/>

I am able to extract values from this XML file like this:

<xsl:value-of select="$Translations/msa:Translations/msa:en/msa:ServiceTalk"/>

The above will pull out the English translation. Here is the thing, in my main XML data file I have the following at the top:

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="Workbook-S-140-Compact_2020_v2.xsl"?>
<MeetingWorkBook>
    <Settings>
        <LanguageCode>en</LanguageCode>
        <Direction>ltr</Direction>
        <EditorMode>1</EditorMode>
        <ForeignGroupMode>0</ForeignGroupMode>
        <Now Day="20" Month="2" Year="2020"/>
    </Settings>

Notice the LanguageCode entry? I wanted to make use of this so that my transformation was based on the language code. So I initially added a second variable to my XSL file:

  <xsl:variable name="LangCode">
    msa:<xsl:value-of select="//Settings//LanguageCode"/>
  </xsl:variable>

And adjusting my path like this:

<xsl:value-of select="$Translations/msa:Translations/{$LangCode}/msa:ServiceTalk"/>

But it doesn't like it. I can't work out how to insert the language code into the path query. I have lots of these translation lines so I am looking for a simple solution if possible.


I have also tried saving the variable as:

  <xsl:variable name="LangCode">
    <xsl:value-of select="//Settings//LanguageCode"/>
  </xsl:variable>

And then using:

<xsl:value-of select="$Translations/msa:Translations/msa:{$LangCode}/msa:ServiceTalk"/>

It still fails.

Is it possible to adjust this line:

<xsl:variable name="Translations" select="document('Workbook-S-140-Compact_2020_v2_Translations.XML')"/>

So that $Translations is pointing to the Translations/langcode node? Make sense?

2 Answers 2

1

You can't use attribute value templates to dynamically construct an XPath expression.

But you can use variables in predicates:

<xsl:value-of select="$Translations/msa:Translations/msa:*[local-name() = $LangCode]/msa:ServiceTalk"/>
Sign up to request clarification or add additional context in comments.

2 Comments

Excellent! Works a charm. Thanks.
Great! :) (For next time, please make a self-contained sample, e.g. on XSLT fiddle. It's really hard to figure out why certain things don't work when the code in the question consists of unrelated three-liners that leave out many important bits.)
1

To expand on @Tomalak's correct answer, you made several mistakes:

Firstly:

  <xsl:variable name="LangCode">
    msa:<xsl:value-of select="//Settings//LanguageCode"/>
  </xsl:variable>

There are several things wrong here. First, the whitespace that precedes "msa:" is part of the value of the variable, and will cause matching to fail. Secondly, using paths with multiple "//" operators is quite unnecessarily expensive. Thirdly, you're constructing a result tree fragment when it would be much simpler to construct a string:

<xsl:variable name="LangCode" select="concat('msa:', //Settings/LanguageCode)"/>

Next, you're misunderstanding the way variables work in XPath. Variables represent values, not parts of expression text (it's not a macro language like a shell script, it's an expression language like Javascript). Your variable can be used wherever you might use a string literal in quotes, for example [contains(., 'fred')] can become contains(., $var). It can't be used in place of parts of the expression where a string literal wouldn't be allowed. And curly braces for textual substitution work only in a few well-defined contexts, they are never used to replace parts of an expression (at least, not until you get to shadow variables in XSLT 3.0, but that's an advanced topic...)

4 Comments

Thanks for sharing. I will have a go with these refinements.
Your sample did not compile. So I tried <xsl:variable name="LangCode" select="concat('msa:', //Settings/LanguageCode)"/> which does compile. But then I tried <xsl:value-of select="$Translations/msa:Translations/*[local-name() = $LangCode]/msa:ScheduleHeading"/> and nothign is showing up.
In the first instance I just had to add that close brace ) to the concat call. But I don't understand why the subsequent attempts to extract values from $Translations were failing.
I must be doing something wrong. But the accepted answer method is working great.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.