Reputation: 561
I have the following XML code (this is a snippet with what I am trying to work with).
<products>
<product>
<productname>Name2</productname>
<productsize measurement="ml">250</productsize>
<productsize measurement="ml">500</productsize>
<productsize measurement="ml">750</productsize>
<otherelements></otherelements>
<price size="250" packsize="1">1.25</price>
<price size="250" packsize="6">7.50</price>
<price size="250" packsize="12">7.00</price>
<price size="500" packsize="1">1.75</price>
<price size="500" packsize="6">10.50</price>
<price size="500" packsize="12">19.00</price>
<price size="750" packsize="1">2.25</price>
<price size="750" packsize="6">13.50</price>
<price size="750" packsize="12">25.00</price>
</product>
<product>
<productname>Name1</productname>
<productsize measurement="ml">250</productsize>
<productsize measurement="ml">750</productsize>
<otherelements></otherelements>
<price size="250" packsize="1">1.25</price>
<price size="250" packsize="6">7.50</price>
<price size="250" packsize="12">7.00</price>
<price size="750" packsize="1">2.25</price>
<price size="750" packsize="6">13.50</price>
<price size="750" packsize="12">25.00</price>
</product>
</products>
What I am trying to do is display it like this
250ml 1=£1.25, 6=£7.50, 12=£7.00
500ml 1=£1.75, 6=£10.50, 12=£19.00
750ml 1=£2.25, 6=£13.50, 12=£25.00
But it's no working and here is my XSL Code what and I doing wrong, I know it's got to do with the inner for loop.
<xsl:for-each select="x:productsize">
<p>
<xsl:value-of select="."/>
<xsl:value-of select="@measurement"/>
</p>
<xsl:for-each select="x:price">
<xsl:if test="productsize = '@size'">
<xsl:value-of select="."/>
</xsl:if>
</xsl:for-each>
</xsl:for-each>
Upvotes: 1
Views: 107
Reputation: 19953
Firstly, your XML is invalid... you cannot have an element called <other elements></other elements>
. And your closing <product>
should be </product>
. But I guess that is just written in there for the question.
The main issue is that <price>
is not WITHIN <productsize>
... therefore when you run <xsl:for-each>
on the productsize
you are searching for effectively /productsize/price
Try this instead...
<xsl:for-each select="product/productsize">
<xsl:variable name="sizevar" select="."/>
<p>
<xsl:value-of select="."/>
<xsl:value-of select="@measurement"/>  
<xsl:for-each select="../price[@size=$sizevar]">
<xsl:value-of select="@packsize"/> =
<xsl:value-of select="."/>,  
</xsl:for-each>
</p>
</xsl:for-each>
This takes the value of the size
attribute from the <productsize>
, and uses it to find those <price>
elements with the same size
attribute
See this XMLPlayground for a working demo
As per the OP's comments, the following line was matching all <price>
elements in the entire document...
<xsl:for-each select="//price[@size=$sizevar]">
So I have changed it to the following, which will only find those elements in the parent (i.e. the <productsize>
element the <price>
elements are children of.)
<xsl:for-each select="../price[@size=$sizevar]">
Upvotes: 4
Reputation: 23637
Assuming your source has a namespace, it should have a xmlns
declaration either in the product
element or some ancestor. I will assume something like this:
<product xmlns="your-namespace">
<productsize measurement="ml">250</productsize>
<productsize measurement="ml">500</productsize>
...
</product>
In that case, you also have to declare that namespace in your XSL:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:x="your-namespace" version="1.0"> ... </xsl:stylesheet>
Then, to obtain the result you want, you can use this stylesheet:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:x="your-namespace" version="1.0">
<xsl:output method="text"/>
<xsl:template match="/">
<xsl:apply-templates select="x:product/x:productsize"/>
</xsl:template>
<xsl:template match="x:productsize">
<xsl:variable name="size" select="."></xsl:variable>
<xsl:value-of select="."/>
<xsl:value-of select="@measurement"/><xsl:text> </xsl:text>
<xsl:apply-templates select="../x:price[@size=$size]"/><xsl:text>
</xsl:text>
</xsl:template>
<xsl:template match="x:price">
<xsl:value-of select="@packsize"/><xsl:text>=£</xsl:text>
<xsl:value-of select="."/>
<xsl:if test="not(position() = last())">
<xsl:text>, </xsl:text>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
As for why your stylesheet didn't work, there are many possible reasons. If the namespaces are correctly declared, you are trying to read price
in the context of productsize
, but they are not nested. You would have to access each price moving out of your context, either using a relative or absolute XPath expression. I used ../price
above, but it would also work with //price
.
I am assuming that any other code you did not post and couldn't be assumed from your examples is not relevant. If you have other product
elements or if products
is not actually root, you will have to adapt the stylesheet.
Upvotes: 2