Topics

calculate color variable based on current chapter #PDF


elementalsource@...
 

Hi all,

OT 2.5.4, PDF. I'm trying to set a variable based on the outputclass value of the current <chapter> element in a bookmap.

bookmap
|_chapter outputclass="foo"
  |_mapref...
|_chapter outputclass="bar"
  |_mapref...

This variable needs to trigger a color change within that chapter. So in chapter 1, I want colorX to be blue and in chapter 2 I want colorX to be red, for example.

Using this:

<xsl:variable name="acme.sectiontype" select="//*[contains(@class, ' bookmap/chapter ')]/@outputclass"/>

It seems that the variable is calculated initially, so that I do get colorX set to blue, but then it's never calculated again, so colorX doesn't change to red in chapter 2.

I suspect that either the subsequent chapter elements are getting lost in the merge or that my xpath is wrong or that I just need to be doing this some other way.

Any ideas?

Many thanks,
Leigh


ekimber@contrext.com
 

Your XPath is selecting every chapter @outputclass value in the document--if you put the value out to a message you should see all the values in the doc.

"//*" at the start of an XPath means "all elements", so "//*[contains(@class, ' bookmap/chapter ')]" selects all bookmap/chapter elements in the document and then "/@outputclass" selects each of their @outputclass attributes.

That's definitely not what you want in this case.

If it was what you wanted, it's still a very inefficient XPath because the XPath engine has to examine every element in the document to see if it might satisfy the predicate. In this case, because we know the rules for BookMap we know that <chapter> can only be the direct child of <bookmap> or of <part>, so you could do:

(/*/*[contains(@class, ' bookmap/chapter ')] | /*/*/*[contains(@class, ' bookmap/chapter ')])/@outputclass

As a rule you should never use "//" as the start of a XPath expression unless you really do not know where the target elements might be. If you need to search all descendants of a context, establish the context first, i.e, "/*/chapter//foo" to find "foo" anywhere under chapter. Usually when you use "//" it's to find descendants of the element that is the current context node for a template.

If you want the value of the current chapter then your selection needs to be relative to the current chapter element, so if the template is matching on <chapter>, the selection to get the @outputclass would simply be select="./@outputclass".

You almost certainly want to put as="xs:string" on the xsl:variable instruction--that will ensure that it's value is the string value of the attribute and not, for example, the attribute node. If you're using the value of the variable in xsl:value-of or an attribute value template it doesn't really matter--those contexts will force the variable to a string but other use contexts could produce an unexpected result.

As a general rule in XSLT 2+, all variables and parameters and functions should specify @as with the datatype they are (or should be). You can also specify @as on templates when the template should return something other than a node, such as a template that produces a string (as distinct from a text node) or a template that produces an attribute.

Using @as makes your intent clearer and also allows for compile-time and runtime checking of the values, which can help prevent hard-to-debug errors.

Cheers,

E.

--
Eliot Kimber
http://contrext.com


On 7/7/20, 10:43 AM, "main@dita-users.groups.io on behalf of elementalsource@gmail.com" <main@dita-users.groups.io on behalf of elementalsource@gmail.com> wrote:

Hi all,

OT 2.5.4, PDF. I'm trying to set a variable based on the outputclass value of the current <chapter> element in a bookmap.

bookmap
|_chapter outputclass="foo"
|_mapref...
|_chapter outputclass="bar"
|_mapref...

This variable needs to trigger a color change within that chapter. So in chapter 1, I want colorX to be blue and in chapter 2 I want colorX to be red, for example.

Using this:

<xsl:variable name="acme.sectiontype" select="//*[contains(@class, ' bookmap/chapter ')]/@outputclass"/>

It seems that the variable is calculated initially, so that I do get colorX set to blue, but then it's never calculated again, so colorX doesn't change to red in chapter 2.

I suspect that either the subsequent chapter elements are getting lost in the merge or that my xpath is wrong or that I just need to be doing this some other way.

Any ideas?

Many thanks,
Leigh