Reputation: 15
Learning XSLT!
I have an XML source tree fragment that looks like this:
Using Saxon and XSLT 2.0 to transform...
<?xml version = "1.0" encoding = "UTF-8"?>
<Chapter revision="B" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Content Ref="X123">
<Ref name="INT1"/>
<Ref name="INT2"/>
<Ref name="INT3"/>
<Ref name="INT4"/>
<Ref name="INT5"/>
</Content>
<Data>
<Reference name="INT1" Function="CONDUCTOR"></Reference>
<Reference name="INT2" Function="SIGNAL"></Reference>
<Reference name="INT3" Function="MIXED"></Reference>
<Reference name="INT4" Function="PLANE"></Reference>
<Reference name="INT5" Function="CORE"></Reference>
</Data>
</Chapter>
I want it to produce this:
<Chapter>
<Content>
<Ref id="INT1" Function="CONDUCTOR">INT1</Ref>
<Ref id="INT2" Function="SIGNAL">INT2</Ref>
<Ref id="INT3" Function="MIXED">INT3</Ref>
<Ref id="INT4" Function="PLANE">INT4</Ref>
<Ref id="INT5" Function="CORE">INT5</Ref>
</Content>
</Chapter>
Here's my template fragment:
<xsl:template match="/">
<xsl:apply-templates select="/Chapter"/>
</xsl:template>
<xsl:template match="/Chapter">
<xsl:element name="{name()}">
<xsl:apply-templates select="Content"/>
</xsl:element>
</xsl:template>
<xsl:template match="Content">
<xsl:element name="{name()}">
<xsl:apply-templates select="Ref"/>
</xsl:element>
</xsl:template>
<xsl:template match="Ref">
<xsl:element name="{name()}">
<xsl:attribute name="id">
<xsl:value-of select="@name"/>
</xsl:attribute>
<xsl:attribute name="Function">
<xsl:value-of select="/Chapter/Data/Reference[@name=/Chapter/Data/Reference/@name]/@Function"/>
</xsl:attribute>
<xsl:value-of select="@name"/>
</xsl:element>
</xsl:template>
But the template above produces this: It is obviously picking up the values from every node
<Chapter>
<Content>
<Ref id="INT1" Function="CONDUCTOR SIGNAL MIXED PLANE CORE">INT1</Ref>
<Ref id="INT2" Function="CONDUCTOR SIGNAL MIXED PLANE CORE">INT2</Ref>
<Ref id="INT3" Function="CONDUCTOR SIGNAL MIXED PLANE CORE">INT3</Ref>
<Ref id="INT4" Function="CONDUCTOR SIGNAL MIXED PLANE CORE">INT4</Ref>
<Ref id="INT5" Function="CONDUCTOR SIGNAL MIXED PLANE CORE">INT5</Ref>
</Content>
</Chapter>
What do I need to supply as a predicate value to step through the attribute values?
Many thanks
Upvotes: 1
Views: 95
Reputation: 167716
Change /Chapter/Data/Reference[@name=/Chapter/Data/Reference/@name]/@Function
to /Chapter/Data/Reference[@name=current()/@name]/@Function
, then learn about keys and define <xsl:key name="ref" match="Data/Reference" use="@name"/>
and use key('ref', @name)/@Function
instead to improve performance and readability.
In general you might want to learn about literal result elements and attribute value templates so that
<xsl:template match="Ref">
<xsl:element name="{name()}">
<xsl:attribute name="id">
<xsl:value-of select="@name"/>
</xsl:attribute>
<xsl:attribute name="Function">
<xsl:value-of select="/Chapter/Data/Reference[@name=/Chapter/Data/Reference/@name]/@Function"/>
</xsl:attribute>
<xsl:value-of select="@name"/>
</xsl:element>
</xsl:template>
becomes
<xsl:template match="Ref">
<Ref id="{@name}" Function="{key('ref', @name)/@Function}">
<xsl:value-of select="@name"/>
</Ref>
</xsl:template>
and the complete code is
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs"
version="2.0">
<xsl:key name="ref" match="Data/Reference" use="@name"/>
<xsl:template match="/Chapter">
<xsl:copy copy-namespaces="no">
<xsl:apply-templates select="Content"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Content">
<xsl:copy copy-namespaces="no">
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
<xsl:template match="Ref">
<Ref id="{@name}" Function="{key('ref', @name)/@Function}">
<xsl:value-of select="@name"/>
</Ref>
</xsl:template>
</xsl:stylesheet>
Upvotes: 0