have got a XML like this:
<?xml version="1.0" encoding="utf-8" ?>
<root xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:skos="http://www.w3.org/2004/02/skos/core#" version="2.8.1" vocab-version="2013-02-28" >
<section1>
<a xml:id="a100">
<ref xlink:href="#aXXX"/>
<ref xlink:href="#aYYY"/>
</a>
</section1>
<section2>
<b xml:id="aXXX">
DataB
</b>
<c xml:id="aYYY">
DataC
</c>
</section2>
</root>
I want to apply the following XSLT:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xlink="http://www.w3.org/1999/xlink">
<xsl:output method="text" indent="yes"/>
<xsl:strip-space elements="*" />
<xsl:preserve-space elements="db:para db:literallayout" />
<xsl:param name="code" />
<xsl:key name='mykeys' match='/root/section2/*' use='concat("#", @xml:id)'/>
<xsl:template match="/" >
<xsl:apply-templates select='/root/section1/a/ref'>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="ref">
<xsl:apply-templates select='key("mykeys", @xlink:href)' >
</xsl:apply-templates>
</xsl:template>
<xsl:template match='b | c' >
<xsl:value-of select="." />
</xsl:template>
</xsl:stylesheet>
I want to have the output something like this :
DataC
DataB
Notice that c’s text should be before b’s text
I think a xsl:sort needs be added to apply-templates , something like this:
<xsl:sort select='/root/section2/*[concat("#", @xml:id)=current()/@xlink:href][local-name()]' order="descending" /
>
i.e.:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:db="http://docbook.org/ns/docbook"
xmlns:xlink="http://www.w3.org/1999/xlink">
<xsl:output method="text" indent="yes"/>
<xsl:strip-space elements="*" />
<xsl:preserve-space elements="db:para db:literallayout" />
<xsl:param name="code" />
<xsl:key name='mykeys' match='/root/section2/*' use='concat("#", @xml:id)'/>
<xsl:template match="/" >
<xsl:apply-templates select='/root/section1/a/ref'>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="ref">
<xsl:apply-templates select='key("mykeys", @xlink:href)' >
<xsl:sort select='/root/section2/*[concat("#", @xml:id)=current()/@xlink:href][local-name()]' order="descending" />
</xsl:apply-templates>
</xsl:template>
<xsl:template match='b | c' >
<xsl:value-of select="." />
</xsl:template>
</xsl:stylesheet>
But it doesn’t work.
Notice that the ordering can’t be based on xml:id as it can be anything and it also cannot be based on the text (i.e. datac , datab , …) as they can be anything so the ordering should be based on Element Name ( i.e. , ) only.
I tried to understand what the actual value of select='/root/section2/*[concat("#", @xml:id)=current()/@xlink:href][local-name()]' is? so I sent it to the template as parameter:
<xsl:template match="a">
<xsl:apply-templates select='key("mykeys", @xlink:href)' >
<xsl:with-param name='testparameter' select='/root/section2/*[concat("#", @xml:id)=current()/@xlink:href][local-name()]' />
</xsl:apply-templates>
</xsl:template>
<xsl:template match='b | c' >
<xsl:param name='testparameter' />
<xsl:value-of select='$testparameter' />
</xsl:template>
And surprising it was not the name of the element , if was the text of each element (i.e. DataB and DataC rather than b and c ) and even the order-type(descending) has not been applied as well.
Can you please help me and let me know how I can get an output like this:
DataC
DataB
Please notice that datac and datab should be accessible only via element and it means I can’t use
apply-templates select='/root/section2/b' or apply-templates select='/root/section2/c'
Thanks,
I think you need to put the xsl:sort
in the apply-templates for the ref
instead.
This seems to work...
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xlink="http://www.w3.org/1999/xlink">
<xsl:output method="text" indent="yes"/>
<xsl:strip-space elements="*" />
<xsl:param name="code" />
<xsl:key name='mykeys' match='/root/section2/*' use='concat("#", @xml:id)'/>
<xsl:template match="/" >
<xsl:apply-templates select='/root/section1/a/ref'>
<xsl:sort select="local-name(key('mykeys', @xlink:href))" order="descending"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="ref">
<xsl:apply-templates select='key("mykeys", @xlink:href)' />
</xsl:template>
<xsl:template match='b | c' >
<xsl:value-of select="." />
</xsl:template>
</xsl:stylesheet>
Also, using [local-name()]
in this context is only checking to see if the element has a local name. I don't think this is what you intended.
If you want to use local-name()
put your XPath as the argument to local-name()
like: local-name(/some/xpath/*)
. (In XPath 2.0/XSLT 2.0 you could also put local-name()
at the end of your path like: /some/xpath/*/local-name()