?
Solved

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

Posted on 2014-09-03
6
Medium Priority
?
182 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 2000 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 2000 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 20

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
Free Tool: Subnet Calculator

The subnet calculator helps you design networks by taking an IP address and network mask and returning information such as network, broadcast address, and host range.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

 
LVL 60

Accepted Solution

by:
Geert Bormans earned 2000 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 20

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

Upgrade your Question Security!

Your question, your audience. Choose who sees your identity—and your question—with question security.

Question has a verified solution.

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

I was working on a PowerPoint add-in the other day and a client asked me "can you implement a feature which processes a chart when it's pasted into a slide from another deck?". It got me wondering how to hook into built-in ribbon events in Office.
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. 
The video will let you know the exact process to import OST/PST files to the cloud based Office 365 mailboxes. Using Kernel Import PST to Office 365 tool, one can quickly import numerous OST/PST files to Office 365. Besides this, the tool also comes…
Free Data Recovery software is an advanced solution from Kernel Tools to recover data and files such as documents, emails, database, media and pictures, etc. It supports recovery from physical & logical drive after a hard disk crash, accidental/inte…

607 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