2

If have a big 'xsl:choose' chunk in which I need to set a number of defined sets of attributes on different elements.

I really do not like to repeat the definition of sets of attributes inside every branch of the 'choose'. So I would like to work with a variable that contains those attributes. A lot easier to maintain and less room for error...

So far I have not been able to call the attribute node out? I thought they are just a node-set, so copy-of would do the trick.
But that gives me nothing on output.
Is this because attribute nodes are not really children?
But XSLT 1.O does not allow me to address them directly...<xsl:copy-of select="$attributes_body/@*/> returns an error

Here is the stylesheet fragment (reduced from original)

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="list">
  <xsl:for-each select="figure">
  <xsl:variable name="attributes_body">
     <xsl:attribute name="chapter"><xsl:value-of select="@chapter"/></xsl:attribute>
     <xsl:attribute name="id"><xsl:value-of select="@id"/></xsl:attribute>
   </xsl:variable>
   <xsl:variable name="attributes_other">
      <xsl:attribute name="chapter"><xsl:value-of select="@book"/></xsl:attribute>
      <xsl:attribute name="id"><xsl:value-of select="@id"/></xsl:attribute>
   </xsl:variable>
    <xsl:choose>
       <xsl:when test="ancestor::body">
          <xsl:element name="entry">
            <xsl:copy-of select="$attributes_body"/>
            <xsl:text>Body fig</xsl:text>
          </xsl:element>
       </xsl:when>
       <xsl:otherwise>
          <xsl:element name="entry">
            <xsl:copy-of select="$attributes_other"/>
            <xsl:text>other fig</xsl:text>
          </xsl:element>
       </xsl:otherwise>
    </xsl:choose>         
  </xsl:for-each>    
</xsl:template>

If this can not be done in XLST 1.0 would 2.0 be able to do this?

4
  • It's not exactly clear to me what you try to achieve. Do you wish to store (and later retrieve) input data from attributes into a variable? If so, what's the input XML/html? And, if so, you will probably just want to use xsl:variable instead of xsl:template. And the nested xsl:variable you are using is wrong. So please add the input and expected output plus approach wrt variable store+retrieval, then we can advise you better. Commented Mar 20, 2012 at 12:44
  • @Maestro13 the intend is to create a list of all 'figure' elements in the document. Depending on the various conditions the list will contain elements that will have preset sets of attributes. Those attributes will have values that depend on each 'figure' element found in the source document. I think what might confuse you was that I re-emitted another figure element. I have edited the original stylesheet so it emits a element with a different name. Commented Mar 20, 2012 at 13:35
  • @Maestro13 And since I do not want to repeat the set of attributes over and over again, I would like to have the sets of attributes stored in different variables. I do hope it makes it all a bit more clear to you. Commented Mar 20, 2012 at 13:39
  • this question could help you stackoverflow.com/questions/9497703/… Commented Jun 12, 2017 at 14:49

2 Answers 2

5
<xsl:variable name="attributes_body"> 
     <xsl:attribute name="chapter"><xsl:value-of select="@chapter"/></xsl:attribute> 
     <xsl:attribute name="id"><xsl:value-of select="@id"/></xsl:attribute> 
 </xsl:variable>

You need to select the wanted attributes -- not to copy their contents in the body of the variable.

Remember: Whenever possible, try always to specify an XPath expression in the select attribute of xsl:variable -- avoid copying content in its body.

Solution:

Just use:

<xsl:variable name="attributes_body" select="@chapter | @id"> 

Here is a complete example:

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

     <xsl:template match="x/a">
      <xsl:variable name="vAttribs" select="@m | @n"/>

      <newEntry>
        <xsl:copy-of select="$vAttribs"/>
        <xsl:value-of select="."/>
      </newEntry>
     </xsl:template>
</xsl:stylesheet>

when applied on this:

<x>
 <a m="1" n="2" p="3">zzz</a>
</x>

produces:

 <newEntry m="1" n="2">zzz</newEntry>
Sign up to request clarification or add additional context in comments.

7 Comments

Novtchev: Attribute-set will not sadly not fly. The values stored inside the attributes have to be read from the selected node in the for-each loop. Since attribute-set is a top level element, I can not see how you will make this happen. Take for example the @id attribute in my example. Its values should be the id of selected 'figure' node in the for-each loop
hmmm...and how do you output this as 2 different attributes on the 'entry' node that sits in the list? I really want output like <entry chapter="2" id="fig6">Body fig</entry>
@HafLinger: Just use <xsl:copy-of select="$attributes_body"/> -- ibefore specifying any other child node for the element. See my updated answer for an example.
@HafLinger: Were you able to understand and use this solution? I updated my answer again, providing more detailed explanation.
Yes, it does work. Great. So does this mean that a variable can only contain nodes from the source tree and I can not create nodes myself? So when I need something like <xsl:attribute name="fignum"><xsl:value-of select="substring-after(@id, 'f')"/></xsl:attribute> I'm out of luck?
|
1

in my case, I was trying to store a tag attribute into a variable

to do so, use this syntax tag-name/@attribute-inside-tag-name

here is an example

<xsl:variable name="articleLanguage" select="/article/@language"/><!--the tricky part  -->
//<!--now you can use this this varialbe as you like  -->
<xsl:apply-templates select="front/article-meta/kwd-group[@language=$articleLanguage]"/>

and the xml was

<article article-type="research-article" language="es" explicit-lang="es" dtd-version="1.0"> 
.....

hope this help you

Comments

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.