handling different namespaces for call-template in xslt - xslt

I am working on call-template, where the source looks like this.
Source:
<Content>
<first>
<text>
Text
</text>
<link xmlns="Some namespace">
<AA>abcd</AA>
<BB>hi all</BB>
</link>
</first>
<second>
<link xmlns="Some other namespace">
<AA>abcd1</AA>
<BB>hi all21</BB>
</link>
</second>
<three>
<link xmlns="other namespace">
<AA>abcd2</AA>
<BB>hi all33</BB>
</link>
</three>
</Content>
XSLT written:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:n1="Some namespace" xmlns:n2="Some other namespace" xmlns:n3="other namespace">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="Content">
<xsl:call-template name="process">
<xsl:with-param name="item" select="first/n1:link" />
</xsl:call-template>
<xsl:call-template name="process">
<xsl:with-param name="item" select="second/n2:link" />
</xsl:call-template>
<xsl:call-template name="process">
<xsl:with-param name="item" select="three/n3:link" />
</xsl:call-template>
</xsl:template>
<xsl:template name="process">
<xsl:param name="item" />
<xsl:value-of select="$item/AA" />
</xsl:template>
</xsl:stylesheet>
I am getting blank output.I know the reason because i didn't append the namespace prefix for it. like "n1:A" like that.
As the is coming multiple times. I wrote a template and called where ever needed. But the name space of each link is diffrent. How to do I modify my code so that I can reuse the template "process".
Can any one help, how Do I modify the "process" template accordingly to handle with diffrent namespace but same structure.
Thank you.

Instead of doing this
<xsl:value-of select="$item/AA" />
You could change the expression to this
<xsl:value-of select="$item/*[local-name() = 'AA'][namespace-uri()=namespace-uri($item)]" />
i.e. Check the name without namespace is 'AA', and that it has the same namespace as the parent element. This would mean if you had another 'AA' element within the 'link' element with a different namespace, it would not be picked up.

It's worth pointing out that this is a poorly designed XML document. Whenever you see someone creating two namespaces N1 and N2 such that the local names in N1 are the same as the local names in N2, you should detect a design smell. They are making the XML much more difficult for people to process.
When I see this kind of input (it sometimes arises if people mistakenly change the namespace URI for version 2 of their vocabulary) I usually reckon that the best approach to processing it is to write a pipeline in which the first phase is to normalize the namespaces, so that the "real" processing logic doesn't have to deal with multiple namespaces in the way your code is doing, which always ends up looking like spaghetti.

Related

Using an xsl param as argument to XPath function

I've been trying to figure out a way to use a param/variable as an argument to a function.
At the very least, I'd like to be able to use basic string parameters as arguments as follows:
<xsl:param name="stringValue" default="'abcdef'"/>
<xsl:value-of select="substring(string($stringValue),1,3)"/>
The above code generates no output.
I feel like I'm missing a simple way of doing this. I'm happy to use exslt or some other extension if an xslt 1.0 processor does not allow this.
Edit:
I am using XSL 1.0 and transforming using Nokogiri, which supports XPATH 1.0 . Here is a more complete snippet of what I am trying to do:
I want to pass column numbers as parameters using nokogiri as follows
document = Nokogiri::XML(File.read('table.xml'))
template = Nokogiri::XSLT(File.read('extractTableData.xsl'))
transformed_document = template.transform(document,
["tableName","'Problems'", #Table Heading
"tablePath","'Table'", #Takes an absolute XPATH String
"nameColumnIndex","2", #column number
"valueColumnIndex","3"]) #column number
File.open('FormattedOutput.xml', 'w').write(transformed_document)
My xsl then wants to access every TD[valueColumnIndex] and and retrieve the first 3 characters at that position, which is why I am using a substring function. So I want to do something like:
<xsl:value-of select="substring(string(TD[$valueColumnIndex]),1,3)"/>
Since I was unable to do that, I tried to extract TD[$valueColumnIndex] to another param valueCode and then do substring(string(valueCode),1,3)
That did not work either (which is to say, no text was output, whereas <xsl:value-of select="$valueCode"/> gave me the expected output).
As a result, i decided to understand how to use parameters better, I would just use a hard coded string, as mentioned in my earlier question.
Things I have tried:
using single quotes around abcdef (and not) while
using string() around the param name (and not)
Based on the comments below, it seems I am handicapped in my ability to understand the error because Nokogiri does not report an error for these situations. I am in the process of installing xsltproc right now and seeing if I receive any errors.
Finally, here is my entire xsl. I use a separate template forLoop because of the valueCode param I am creating. The lines of interest are the last 5 or so. I cannot include the xml as there are data use issues involved.
<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ext="http://exslt.org/common"
xmlns:dyn="http://exslt.org/dynamic"
exclude-result-prefixes="ext dyn">
<xsl:param name="tableName" />
<xsl:param name="tablePath" />
<xsl:param name= "nameColumnIndex" />
<xsl:param name= "valueColumnIndex"/>
<xsl:template match="/">
<xsl:param name="tableRowPath">
<xsl:value-of select="$tablePath"/><xsl:text>/TR</xsl:text>
</xsl:param>
<!-- Problems -->
<section>
<name>
<xsl:value-of select="$tableName" />
</name>
<!-- <xsl:for-each select="concat($tablePath,'/TR')"> -->
<xsl:for-each select="dyn:evaluate($tableRowPath)">
<!-- Encode record section -->
<xsl:call-template name="forLoop"/>
</xsl:for-each>
</section>
</xsl:template>
<xsl:template name="forLoop">
<xsl:param name="valueCode">
<xsl:value-of select="./TD[number($valueColumnIndex)][text()]"/>
</xsl:param>
<xsl:param name="RandomString" select="'Try123'"/>
<section>
<name>
<xsl:value-of select="./TD[number($nameColumnIndex)]"/>
</name>
<code>
<short>
<xsl:value-of select="substring(string($valueCode),1,3)"/>
</short>
<long>
<xsl:value-of select="$valueCode"/>
</long>
</code>
</section>
</xsl:template>
</xsl:stylesheet>
Use it this way:
<xsl:param name="stringValue" select="'abcdef'"/>
<xsl:value-of select="substring($stringValue,1,3)"/>

Like xsl:value-of, but with a space or dot at element boundaries

I'll bet there is a clever, terse way to do this.
<xsl:call-template name="item">
<xsl:with-param name="name" ><xsl:value-of select="name()" /></xsl:with-param>
<xsl:with-param name="value"><xsl:value-of select="." /></xsl:with-param>
</xsl:call-template>
See the xsl:value-of select="." Usually all is well. But sometimes, the current node will have children and the text all runs together when I'd like some break:
The Right Stuff<line/>Tom Wolfe
or
<title>The Right Stuff</title><author>Tom Wolfe</author>
In these cases, I'd like a space or dot or something between "Stuff" and "Tom".
How could I say xsl:value-of select="." but add a space instead of running node contents together?
Firstly, never write this:
<xsl:with-param name="name" ><xsl:value-of select="name()" /></xsl:with-param>
when you could write this:
<xsl:with-param name="name" select="name()" />
It's not only verbose, its also grossly inefficient to construct a temporary tree in memory when you only need a simple string. Sadly, this mistake seems to be becoming ever more common.
xsl:value-of, when given an element, extracts the string value of the element, which is the concatenation of the text nodes. This is convenient when people are using the common and familiar markup design for mixed content where stripping all the tags leaves you with human-readable content. If the XML hasn't been designed to use this convention, then this rule for the string value is less useful (which is why, in schema-aware XPath, you aren't allowed to get the string value of an element unless it is defined with simple content or mixed content).
In your case I would suggest passing the element node as a parameter, rather than its string value, and in the called template using apply-templates to process the content of the element node.
When we use <xsl:value-of select="."/> then it puts the value of the context node as well as all the child nodes. I don't think we can simply add a "." or "space" between the text values.
However, we can implement it in such a way that we iterate over such child nodes and therby get a chance to add a "." or "space".
Let's assume your XML looks like the following.
<?xml version="1.0" encoding="UTF-8"?>
<root>
<item>
<title>The Right Stuff</title><author>Tom Wolfe</author>
</item>
</root>
Then, you can use the following XSL to put a "." after the values of child nodes.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes" method="xml" />
<xsl:template match="/">
<xsl:call-template name="Item">
<xsl:with-param name="name" select="name()"/>
<xsl:with-param name="value" select="//item[1]"/>
</xsl:call-template>
</xsl:template>
<xsl:template name="Item">
<xsl:param name="name" />
<xsl:param name="value" />
<xsl:for-each select="$value/*">
<xsl:value-of select="."/>.
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
I hope this helps.
Write this whenever you need spaces:
<xsl:text> </xsl:text>

How to loop through a list of nodes and create new nodes based on the child nodes of those I'm looping through

This may be a basic question but this newbie has been struggling and Googling and hasn't been able to figure it out.
I have an xml document similar to this.
<x99:events xmlns:x99="http://www.foo.com/x99" xmlns:xl="http://www.w3.org/1999/xlink" pubdate="2012-05-29T11:14:14-06:00">
<x99:event xl:href="event.xml?event_id=255918" id="foo" status="new">
<x99:event_id>255918</x99:event_id>
<x99:custom_attribute xmlns:x99="http://www.foo.com/x99" status="new">
<x99:attribute_id>22</x99:attribute_id>
<x99:attribute_value>hi there</x99:attribute_value>
</x99:custom_attribute>
<x99:custom_attribute xmlns:x99="http://www.foo.com/x99" status="new">
<x99:attribute_id>26</x99:attribute_id>
<x99:attribute_value>this is a test</x99:attribute_value>
</x99:custom_attribute>
<x99:custom_attribute xmlns:x99="http://www.foo.com/x99" status="new">
<x99:attribute_id>12</x99:attribute_id>
<x99:attribute_value>Yes</x99:attribute_value>
</x99:custom_attribute>
</x99:event>
</x99:events>
And I have some xsl that transforms the xml.
In my xsl I need to be able to loop through the custom_attribute nodes and, for each attribute_id I find I need to create a node with some values based on child nodes of the custom_attribute node.
Here's my pseudo-code. I need something like this.
<xsl:for-each select="x99:custom_attribute">
<xsl:when test="number(x99:attribute_id) = 22>
<x99:text>You chose twenty two and your attribute value is <x99:attribute_value></x99:text>
</xsl:when>
<xsl:when test="number(x99:attribute_id) = 26>
<x99:text>Twenty six is a great answer! and your attribute value is <x99:attribute_value></x99:text></x99:text>
</xsl:when>
</xsl:for-each>
And here is my xsl.
My xsl skills are at the most basic level and my xml isn't much better either. Can some kind soul give me some advice? I'm in a bit over my head.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0"
xmlns:xl="http://www.w3.org/1999/xlink"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xhtml="http://www.w3.org/1999/xhtml"
xmlns:b="http://www.someurl.com/b"
xmlns:s="http://www.someurl.com/s"
xmlns:c="http://foo.com/c"
xmlns:x99="http://foo.com/x99"
exclude-result-prefixes="xl x99">
<xsl:param name="base_url" select="''" />
<xsl:param name="session_id" select="''" />
<xsl:param name="TaskDir" select="''" />
<xsl:template match="/">
<xsl:call-template name="SendConfirmationEmail">
<xsl:with-param name="EventID" select="/x99:events/x99:event/x99:event_id"/>
<xsl:with-param name="SiteURL" select="'https://foobar.com/123Test/#details'" />
</xsl:call-template>
<xsl:apply-templates select="node()" />
</xsl:template>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()" />
</xsl:copy>
</xsl:template>
<xsl:template name="SendConfirmationEmail">
<xsl:param name="EventID" select="''"/>
<xsl:result-document>
<schedule>
<job>
<name>Email Confirmation</name>
<active>T</active>
<http>
<body>
<x99:email xmlns:x99="http://foo.com/x99">
<x99:mail>
<x99:body>
<x99:text>Your event ID is <xsl:value-of select="$EventID"/></x99:text>
// I want to be able to loop through my x99:attribute_id values here and create new x99:text nodes.
</x99:body>
</x99:mail>
</x99:email>
</body>
</http>
</job>
</schedule>
</xsl:result-document>
</xsl:template>
</xsl:stylesheet>
So frankly I need to know how to...
Loop through the custom_attribute nodes and for each node create a x99:text node that contains
a string based on the value of the child attribute_id
the contents of the attribute_value node
First, instead of using a named template with parameters as if you were programming in FORTRAN using CALL to invoke subroutines, just define a template to handle the event_id element, such as <xsl:template match="event_id">. I assume you mean html, not http. You'll need to specify a href attribute on the <xsl:result-document> element so it knows where to put the document. You're apparently writing elements into your HTML from the x99 namespace--is that really what you want to do?
With regard to "looping" over the attribute elements, in an XSLT mindset it would be preferable to say "process" them. Under <x99:text> add a <xsl:apply-templates/> element, then define a template to handle the custom attribute elements (<xsl:template match="x99:custom-attribute">. Within that template, place something like what you have within the for-each of your pseudo-code, except that instead of saying number(x99:attribute_id) you'll just want number(.) since we are already at that node. However, note that <xsl:when> elements can only go within a <xsl:choose>.

Calling the same xsl:template for different node names of the same complex type

I'm trying to keep my xsl DRY and as a result I wanted to call the same template for 2 sections of an XML document which happen to be the same complex type (ContactDetails and AltContactDetails). Given the following XML:
<?xml version="1.0" encoding="UTF-8"?>
<RootNode>
<Name>Bob</Name>
<ContactDetails>
<Address>
<Line1>1 High Street</Line1>
<Town>TownName</Town>
<Postcode>AB1 1CD</Postcode>
</Address>
<Email>test#test.com</Email>
</ContactDetails>
<AltContactDetails>
<Address>
<Line1>3 Market Square</Line1>
<Town>TownName</Town>
<Postcode>EF2 2GH</Postcode>
</Address>
<Email>bob#bob.com</Email>
</AltContactDetails>
</RootNode>
I wrote an XSL Stylesheet as follows:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="/">
<PersonsName>
<xsl:value-of select="RootNode/Name"/>
</PersonsName>
<xsl:call-template name="ContactDetails">
<xsl:with-param name="data"><xsl:value-of select="RootNode/ContactDetails"/></xsl:with-param>
<xsl:with-param name="elementName"><xsl:value-of select="'FirstAddress'"/></xsl:with-param>
</xsl:call-template>
<xsl:call-template name="ContactDetails">
<xsl:with-param name="data"><xsl:value-of select="RootNode/AltContactDetails"/></xsl:with-param>
<xsl:with-param name="elementName"><xsl:value-of select="'SecondAddress'"/></xsl:with-param>
</xsl:call-template>
</xsl:template>
<xsl:template name="ContactDetails">
<xsl:param name="data"></xsl:param>
<xsl:param name="elementName"></xsl:param>
<xsl:element name="{$elementName}">
<FirstLine>
<xsl:value-of select="$data/Address/Line1"/>
</FirstLine>
<Town>
<xsl:value-of select="$data/Address/Town"/>
</Town>
<PostalCode>
<xsl:value-of select="$data/Address/Postcode"/>
</PostalCode>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
When i try to run the style sheet it's complaining to me that I need to:
To use a result tree fragment in a path expression, either use exsl:node-set() or specify version 1.1
I don't want to go to version 1.1.. So does anyone know how to get the exsl:node-set() working for the above example?
Or if someone knows of a better way to apply the same template to 2 different sections then that would also really help me out?
Thanks
Dave
You are rolling this up from the wrong end (the wrong end being nearly always: trying to apply the imperative programming paradigm to XSLT).
This is really easy to do via template matching.
<xsl:template match="RootNode">
<PersonsName>
<xsl:value-of select="Name"/>
</PersonsName>
<xsl:apply-templates select="ContactDetails|AltContactDetails" />
</xsl:template>
<xsl:template match="ContactDetails|AltContactDetails">
<xsl:copy>
<FirstLine>
<xsl:value-of select="Address/Line1"/>
</FirstLine>
<Town>
<xsl:value-of select="Address/Town"/>
</Town>
<PostalCode>
<xsl:value-of select="Address/Postcode"/>
</PostalCode>
</xsl:copy>
</xsl:template>
Let go of the notion that you have to tell the XSLT processor what to do (through making named templates and calling them, "imperative style").
The XSLT processor chooses what templates to call. Starting at the root (/) it recursively checks for matching templates for every node it visits. It traverses your input XML all on its own - your only job is it to supply it with matching templates for those nodes you want to have processed in a special way.
You can drop in a custom template for those nodes that need special treatment and trust your XSLT processor with calling it once they come up. All you need to make sure in your templates is that traversal goes on by declaring an appropriate <xsl:apply-templates />.
Why not make the template
<xsl:template match="ContactDetails|AltContactDetails">
and do the test to determine the output element name inside the template instead?

XSLT 2.0 External lookup using key() and document()

I'm pulling what's left of my hair out trying to get a simple external lookup working using Saxon 9.1.0.7.
I have a simple source file dummy.xml:
<something>
<monkey>
<genrecode>AAA</genrecode>
</monkey>
<monkey>
<genrecode>BBB</genrecode>
</monkey>
<monkey>
<genrecode>ZZZ</genrecode>
</monkey>
<monkey>
<genrecode>ZER</genrecode>
</monkey>
</something>
Then the lookup file is GenreSet_124.xml:
<GetGenreMappingObjectsResponse>
<tuple>
<old>
<GenreMapping DepartmentCode="AAA"
DepartmentName="AND - NEWS AND CURRENT AFFAIRS"
Genre="10 - NEWS"/>
</old>
</tuple>
<tuple>
<old>
<GenreMapping DepartmentCode="BBB"
DepartmentName="AND - NEWS AND CURRENT AFFAIRS"
Genre="11 - NEWS"/>
</old>
</tuple>
... lots more
</GetGenreMappingObjectsResponse>
What I'm trying to achieve is simply to get hold of the "Genre" value based on the "DepartmentCode" value.
So my XSL looks like:
...
<!-- Set up the genre lookup key -->
<xsl:key name="genre-lookup" match="GenreMapping" use="#DepartmentCode"/>
<xsl:variable name="lookupDoc" select="document('GenreSet_124.xml')"/>
<xsl:template match="/something">
<stuff>
<xsl:for-each select="monkey">
<Genre>
<xsl:apply-templates select="$lookupDoc">
<xsl:with-param name="curr-label" select="genrecode"/>
</xsl:apply-templates>
</Genre>
</xsl:for-each>
</stuff>
</xsl:template>
<xsl:template match="GetGenreMappingObjectsResponse">
<xsl:param name="curr-genrecode"/>
<xsl:value-of select="key('genre-lookup', $curr-genrecode)/#Genre"/>
</xsl:template>
...
The issue that I have is that I get nothing back. I currently just get
<?xml version="1.0" encoding="UTF-8"?>
<stuff>
<Genre/>
<Genre/>
<Genre/>
<Genre/>
</stuff>
I have moved all the lookup data to be attributes of GenreMapping, previously as child elements of GenreMapping whenever I entered the template match="GetGenreMappingObjectsResponse" it would just print out all text from every GenreMapping (DepartmentCode, DepartmentName, Genre)!
I can't for the life of me figure out what I am doing wrong. Any helpo/suggestions would be greatly appreciated.
PLease find the current actual XSLT listing:
<?xml version="1.0"?>
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<!-- Define the global parameters -->
<xsl:param name="TransformationID"/>
<xsl:param name="TransformationType"/>
<!-- Specify that XML is the desired output type -->
<xsl:output method="xml" encoding="UTF-8" indent="yes"/>
<!-- Set up the genre matching capability -->
<xsl:key name="genre-lookup" match="GenreMapping" use="#DepartmentCode"/>
<xsl:variable name="documentPath"><xsl:value-of select="concat('GenreSet_',$TransformationID,'.xml')"/></xsl:variable>
<xsl:variable name="lookupDoc" select="document($documentPath)"/>
<!-- Start the first match on the Root level -->
<xsl:template match="/something">
<stuff>
<xsl:for-each select="monkey">
<Genre>
<xsl:apply-templates select="$lookupDoc/*">
<xsl:with-param name="curr-genrecode" select="string(genrecode)"/>
</xsl:apply-templates>
</Genre>
</xsl:for-each>
</stuff>
</xsl:template >
<xsl:template match="GetGenreMappingObjectsResponse">
<xsl:param name="curr-genrecode"/>
<xsl:value-of select="key('genre-lookup', $curr-genrecode, $lookupDoc)/#Genre"/>
</xsl:template>
</xsl:stylesheet>
The TransformationID is alway 124 (so the correct lookup file is opened. The Type is just a name that I am currently not using but intending to.
In XSLT 2.0 there are two ways you can do what you want:
One is the three-parameter version of the key function. The third parameter lets you specify the root node you want the key to work on (by default it's always the root of the main document):
<xsl:value-of select="key('genre-lookup', $curr-genrecode,$lookupDoc)/#Genre"/>
Another way is to use the key function under the $lookupDoc node:
<xsl:value-of select="$lookupDoc/key('genre-lookup', $curr-genrecode)/#Genre"/>
Both of these methods are documented in the XSLT 2.0 specification on keys, and won't work in XSLT 1.0.
For the sake of completeness, you'd have to rewrite this to not use keys if you're restricted to XSLT 1.0.
<xsl:value-of select="$lookupDoc//GenreMapping[#DepartmentCode = $curr-genrecode]/#Genre"/>
Aha! The problem is the select="$lookupDoc" in your apply-templates call is calling a default template rather than the one you expect, so the parameter is getting lost.
Change it to this:
<xsl:apply-templates select="$lookupDoc/*">
<xsl:with-param name="curr-genrecode" select="string(genrecode)"/>
</xsl:apply-templates>
That will call your template properly and the key should work.
So the final XSLT sheet should look something like this:
<xsl:variable name="lookupDoc" select="document('XMLFile2.xml')"/>
<xsl:key name="genre-lookup" match="GenreMapping" use="#DepartmentCode"/>
<xsl:template match="/something">
<stuff>
<xsl:for-each select="monkey">
<Genre>
<xsl:apply-templates select="$lookupDoc/*">
<xsl:with-param name="curr-genrecode" select="string(genrecode)"/>
</xsl:apply-templates>
</Genre>
</xsl:for-each>
</stuff>
</xsl:template>
<xsl:template match="GetGenreMappingObjectsResponse">
<xsl:param name="curr-genrecode"/>
<xsl:value-of select="key('genre-lookup',$curr-genrecode,$lookupDoc)/#Genre"/>
</xsl:template>
OK, so this is a bit mental and I don't claim to understand it but it works (sounds like a career in software).
The issue I was having is that when I call the apply-templates and pass in the external document as a variable it never matched any templates even ones called "Genremapping".
So I used a wildcard to catch it, also when calling the apply-templates I narrowed down the node set to be the child I was interested in. This was pretty bonkers a I could print out the name of the node and see "GenreMapping" yet it never went into any template I had called "GenreMapping" choosing instead to only ever go to "*" template.
What this means is that my new template match gets called for every single GenreMapping node there is so it may be a little inefficient. What I realised then was all I needed to do was print sometihng out if a predicate matched.
So it looks like this now (no key used whatsoever):
...
<xsl:template match="/something">
<stuff>
<xsl:for-each select="monkey">
<Genre>
<key_value><xsl:value-of select="genrecode"/></key_value>
<xsl:variable name="key_val"><xsl:value-of select="genrecode"/></xsl:variable>
<code>
<xsl:apply-templates select="$lookupDoc/*/*/*/*">
<xsl:with-param name="curr-genrecode" select="string(genrecode)"/>
</xsl:apply-templates>
</code>
</Genre>
</xsl:for-each>
</stuff>
</xsl:template >
<xsl:template match="*">
<xsl:param name="curr-genrecode"/>
<xsl:value-of select=".[#DepartmentCode = $curr-genrecode]/#Genre"/>
</xsl:template>
...
All of which output:
Note, the last key_value correctly doesn't have a code entry as there is no match in the lookup document.
<?xml version="1.0" encoding="UTF-8"?>
<stuff xmlns:xs="http://www.w3.org/2001/XMLSchema">
<Genre>
<key_value>AAA</key_value>
<code>10 - NEWS</code>
</Genre>
<Genre>
<key_value>AAA</key_value>
<code>10 - NEWS</code>
</Genre>
<Genre>
<key_value>BBB</key_value>
<code>11 - NEWS</code>
</Genre>
<Genre>
<key_value>SVVS</key_value>
<code/>
</Genre>
</stuff>
Answer on a postcode. Thanks for the help Welbog.