XSL Transform, select in namespace prefix?
I am trying to select a node from the following xml that has a namespace prefix:
<gesmes:Envelope xmlns:gesmes="http://www.gesmes.org/xml/2002-08-01">
<Cube>
<Cube time="2009-10-12">
<Cube currency="USD" rate="1.4765"/>
.............................
The xsl I'm using is (Updated): The original xml is at: http://www.ecb.europa.eu/stats/eurofxref/eurofxref-hist-90d.xml
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:gesmes="http://www.gesmes.org/xml/2002-08-01" xmlns="http://www.ecb.int/vocabulary/2002-08-01/eurofxref" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="/">
<xdoc>
<ccurency>
<xsl:for-each select="gesmes:Envelope/Cube/Cube">
<xsl:variable name="atime" select="@time"/>
<xsl:for-each select="Cube">
<row>
<xsl:element name="Date">
<xsl:value-of select="$atime"/>
</xsl:element>
<xsl:element name="Currency">
<xsl:value-of select="@currency"/>
</xsl:element>
<xsl:element name="Rate">
<xsl:value-of select="@rate"/>
</xsl:element>
</row>
</xsl:for-each>
</xsl:for-each>
</ccurency>
</xdoc>
</xsl:template>
</xsl:stylesheet>
It doesn't work, the selection is empty. If I change gesmes: Envelope to simple Envelope in both xml and xsl does everything work fine?
How can I select it with a prefix?
source to share
You seem to be looking for something like this:
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:gesmes="http://www.gesmes.org/xml/2002-08-01"
xmlns:exr="http://www.ecb.int/vocabulary/2002-08-01/eurofxref"
exclude-result-prefixes="gesmes exr"
>
<xsl:output method="xml" indent="yes" encoding="utf-8" />
<xsl:template match="gesmes:Envelope">
<xdoc>
<ccurency>
<xsl:apply-templates select="exr:Cube/exr:Cube/exr:Cube" />
</ccurency>
</xdoc>
</xsl:template>
<xsl:template match="exr:Cube[@currency and @rate]">
<row>
<Date>
<xsl:value-of select="../@time" />
</Date>
<Currency>
<xsl:value-of select="@currency" />
</Currency>
<Rate>
<xsl:value-of select="@rate" />
</Rate>
</row>
</xsl:template>
</xsl:stylesheet>
When applied to your input XML, it produces:
<xdoc>
<ccurency>
<row>
<Date>2009-07-16</Date>
<Currency>PHP</Currency>
<Rate>67.739</Rate>
</row>
<row>
<Date>2009-07-16</Date>
<Currency>SGD</Currency>
<Rate>2.0501</Rate>
</row>
<row>
<Date>2009-07-16</Date>
<Currency>THB</Currency>
<Rate>48.13</Rate>
</row>
<row>
<Date>2009-07-16</Date>
<Currency>ZAR</Currency>
<Rate>11.4575</Rate>
</row>
</ccurency>
</xdoc>
Notes:
- Do not use
<xsl:for-each>
whenever possible. It looks more familiar and less intimidating than it<xsl:apply-templates>
, but it's not the best option in most cases. - You don't need to create elements with
<xsl:element>
, you can write them directly. - You don't need to store the variable with that value
@time
that interests you. You can always refer to the parent node and directly from there from it (../@time
) - I used
exclude-result-prefixes
to make the namespace disappear from the output entirely, you seem to want to get rid of them.
source to share
Make sure you declare the namespace at the root of the transform:
<xsl:stylesheet xmlns:gesmes="http://www.gesmes.org/xml/2002-08-01" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
Looking at your logic and XML input, it appears to be internal to everyone, which will never select nodes as the context changed to internal element <cube>
, namespace or not. It might just be the result of shortening your XML for the question, though ...
source to share