Solved

Use an XSLT variable to access an element in a specific part of an XML tree

Posted on 2014-09-03
6
171 Views
Last Modified: 2014-09-03
I'm using XSLT 1.0 (with lxml.etree and Python) to transform XML.  I can use "http://exslt.org/" extensions (common, strings and so on), but not XSLT 2.0.

The input XML has two main sections - a series of nested rules which have name="xxx" attributes, and a set of mappings that extend the definition of each "xxx".  The XML look like:
<process>
    <rules>
        <generalrule>
            <onerule name="xxx" startval="1" endval="5" maptype="full"/>
            <onerule name="yyy" startval="1" endval="5" maptype="full"/>
        </generalrule>
        <otherrule>
            <thisrule name="yyy" startval="1" endval="5" maptype="partial"/>
        </otherrule>
    </rules>
    <maps>
        <onemap name="xxx" attr1="8">
        <onemap name="yyy" attr1="4">
    </maps>
</process>

Open in new window

As you can see, the rule names can appear multiple times in the "rules" section, but will only appear once in the "maps" section.  The format is fixed - I'd love to change it but cannot.

I already have code in my templates which gets a map entry when parsing an entry from the main rules section, assuming that the element has a "name=" attribute:
<xsl:variable name="myattr1" select="/process/maps/onemap[@name = current()/@name]/@attr1" />

Open in new window

and I can then use the $myattr1 variable in the rest of the template.

What I am trying to do now is to get the attr1 attribute for an entry based on a variable name, not on being the current rule being parsed.  The variable value is actually being extracted from another attribute which has a comma-separated string of map names.

What do I need to replace the "[@name = current()/@name]" section with, to base the selection on the values of, say, the $first xsl variable?  Or do I need to do this a different way?

I have tried the simplistic ways - "[@name = $first]", "[@name = $first/@name]" and so on, and have tried using select="dyn:evaluate('/process/maps/onemap[@name = $first]/@name')"  (after adding xmlns:dyn="http://exslt.org/dynamic" to the stylesheet header).  They all either return nothing, or an evaluation error.  I keep thinking that there is something obvious that I am missing.
0
Comment
Question by:simon3270
  • 4
  • 2
6 Comments
 
LVL 60

Assisted Solution

by:Geert Bormans
Geert Bormans earned 500 total points
ID: 40301479
for that we have keys

keys put an index on elements in the document.
Fetching the element after is cheap

declare a key at the top level of your stylesheet
   <xsl:key name="map" match="maps/onemap" use="@name"/>

and use it like this
    <xsl:template match="onerule">
        <xsl:value-of select="key('map', @name)/@attr1"></xsl:value-of>
    </xsl:template>
0
 
LVL 60

Assisted Solution

by:Geert Bormans
Geert Bormans earned 500 total points
ID: 40301505
Ah OK, I think I missed one thing here.
Bottom line: use the key to not having to use variables

If the name of the attribute you need is in the $first variable

<xsl:value-of select="key('map', @name)/@*[name() = $first]"></xsl:value-of>

Try to avoid dynamic XPath at ALL cost
0
 
LVL 19

Author Comment

by:simon3270
ID: 40301539
It's not the name of the attribute that is is in $first, but the value of the "name=" in the maps/onemap elements, e.g. if $first contains "yyy", we want the value in
     /process/maps/onemap[@name = yyy]/@attr1
0
DevOps Toolchain Recommendations

Read this Gartner Research Note and discover how your IT organization can automate and optimize DevOps processes using a toolchain architecture.

 
LVL 60

Accepted Solution

by:
Geert Bormans earned 500 total points
ID: 40301626
In the template you don't need a variable, but you can address the attribute in its context, as I showed in my first response
<xsl:value-of select="key('map', @name)/@attr1"></xsl:value-of>
or alternatively
<xsl:value-of select="key('map', $first)/@attr1"></xsl:value-of>
0
 
LVL 19

Author Closing Comment

by:simon3270
ID: 40302187
Geert, as always, masterful!  I'm still getting to grips with XSLT (it's not easy getting an old C hacker to use functional programming!), but your answers are a great teaching aid.  Many thanks.
0
 
LVL 60

Expert Comment

by:Geert Bormans
ID: 40302220
Welcome (and don't worry, you will be fine, I started off as a C-hacker as well :-)
0

Featured Post

DevOps Toolchain Recommendations

Read this Gartner Research Note and discover how your IT organization can automate and optimize DevOps processes using a toolchain architecture.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

The Confluence of Individual Knowledge and the Collective Intelligence At this writing (summer 2013) the term API (http://dictionary.reference.com/browse/API?s=t) has made its way into the popular lexicon of the English language.  A few years ago, …
Many times as a report developer I've been asked to display normalized data such as three rows with values Jack, Joe, and Bob as a single comma-separated string such as 'Jack, Joe, Bob', and vice versa.  Here's how to do it. 
This Micro Tutorial will teach you how to censor certain areas of your screen. The example in this video will show a little boy's face being blurred. This will be demonstrated using Adobe Premiere Pro CS6.
This tutorial gives a high-level tour of the interface of Marketo (a marketing automation tool to help businesses track and engage prospective customers and drive them to purchase). You will see the main areas including Marketing Activities, Design …

867 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

16 Experts available now in Live!

Get 1:1 Help Now