I would like to transfrom xml file to another using php through xslt.
On the output I need some adjustments, but I don’t know how to adjust my xsl stylesheet.
Thanks for your help
Needed adjustments on the output:
- add dynamic counting to category element like
<category1> <category2>… - add all content of element SIZE of PRODUCT/COLORS/COLOR/AVAILABLE_SIZE to
<$color>element like<green>S:M:L:XL</green> <orange>L:M</orange> - add dynamic counting to image element like
<image1> <image2>
source xml:
<?xml version="1.0" encoding="utf-8"?>
<PRODUCTS>
<PRODUCT>
<CODE>19</CODE>
<NAME>daisy</NAME>
<MANUFACTURER>79</MANUFACTURER>
<DESCRIPTION>t-shirt</DESCRIPTION>
<SIZES></SIZES>
<PRICE>33.33</PRICE>
<PRICE_AKCIA>24.17</PRICE_AKCIA>
<CATEGORY_ID>42</CATEGORY_ID>
<CATEGORIES>
<CATEGORY>clothes</CATEGORY>
<CATEGORY>t-shirt</CATEGORY>
<CATEGORY>latest</CATEGORY>
</CATEGORIES>
<COLORS>
<COLOR>
<NAME>green</NAME>
<IMAGE>http://www.xyz.com/userfiles/daisy_green.png</IMAGE>
<AVAILABLE_SIZES>
<SIZE>S</SIZE>
<SIZE>M</SIZE>
</AVAILABLE_SIZES>
<SIZES>
<SIZE>S</SIZE>
<SIZE>M</SIZE>
<SIZE>L</SIZE>
<SIZE>XL</SIZE>
</SIZES>
</COLOR>
<COLOR>
<NAME>orange</NAME>
<IMAGE>http://www.xyz.com/userfiles/daisy_orange.png</IMAGE>
<AVAILABLE_SIZES>
<SIZE>L</SIZE>
<SIZE>M</SIZE>
</AVAILABLE_SIZES>
<SIZES>
<SIZE>S</SIZE>
<SIZE>M</SIZE>
<SIZE>L</SIZE>
<SIZE>XL</SIZE>
</SIZES>
</COLOR>
</COLORS>
</PRODUCT>
</PRODUCTS>
xsl stylesheet:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="/">
<xsl:element name="products">
<xsl:apply-templates select="PRODUCTS/PRODUCT"/>
</xsl:element>
</xsl:template>
<xsl:template match="PRODUCTS/PRODUCT">
<xsl:element name="product">
<xsl:element name="id">
<xsl:value-of select="CODE"/>
</xsl:element>
<xsl:element name="name">
<xsl:value-of select="NAME"/>
</xsl:element>
<xsl:element name="model">
<xsl:value-of select="CODE"/>
</xsl:element>
<xsl:element name="manufacturer">
<xsl:value-of select="MANUFACTURER"/>
</xsl:element>
<xsl:element name="category_id">
<xsl:value-of select="CATEGORY_ID"/>
</xsl:element>
<xsl:apply-templates select="CATEGORIES"/>
<xsl:element name="description">
<xsl:value-of select="DESCRIPTION"/>
</xsl:element>
<xsl:element name="price">
<xsl:value-of select="PRICE"/>
</xsl:element>
<xsl:element name="special">
<xsl:value-of select="PRICE_AKCIA"/>
</xsl:element>
<xsl:apply-templates select="COLORS/COLOR"/>
<xsl:apply-templates select="COLORS"/>
</xsl:element>
</xsl:template>
<xsl:template match="CATEGORIES">
<xsl:for-each select="CATEGORY">
<xsl:element name="category">
<xsl:value-of select="."/>
</xsl:element>
</xsl:for-each>
</xsl:template>
<xsl:template match="COLORS">
<xsl:for-each select="COLOR/NAME">
<xsl:variable name="color" select="." />
<xsl:element name="{$color}">
<xsl:apply-templates select="COLOR/AVAILABLE_SIZES"/>
</xsl:element>
</xsl:for-each>
</xsl:template>
<xsl:template match="COLORS/COLOR">
<xsl:for-each select="IMAGE">
<xsl:element name="image">
<xsl:value-of select="."/>
</xsl:element>
</xsl:for-each>
</xsl:template>
<xsl:template match="COLOR/AVAILABLE_SIZES">
<xsl:for-each select="SIZE">
<xsl:value-of select="."/>:
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
result:
<?xml version="1.0" encoding="UTF-8"?>
<products>
<product>
<id>19</id>
<name>daisy</name>
<model>19</model>
<manufacturer>79</manufacturer>
<category_id>42</category_id>
<category>clothes</category>
<category>t-shirt</category>
<category>latest</category>
<description>t-shirt</description>
<price>33.33</price>
<special>24.17</special>
<image>http://www.xyz.com/userfiles/daisy_green.png</image>
<image>http://www.xyz.com/userfiles/daisy_orange.png</image>
<green/>
<orange/>
</product>
</products>
If you want to have dynamically named elements, you can make use of Attribute Value Templates to specify the element name.
So, if you wanted category1, category2, etc, instead of just category you would do this
The curly braces indicate this is an expression to be evalulated.
However, if you were to do this directly with your code for images, you would see they would all be suffixed by 1.
This is because you are getting the position of the IMAGE element within the COLOR element. Really you want the position of the parent COLOR element. Instead, it might be better to match the COLORS element here, then you could get the position of the COLOR element.
Of course, this means you end up with two templates matching COLORS so you probably want to combine them. However, there is a problem with the other template. You are iterating over COLOR/NAME, which means you will be positioned on a NAME element within the loop. Therefore when you try to select COLOR/AVAILABLE_SIZES it is looking for them below the current element, where they don’t exist. You should probably be doing this
A couple of other things to note. You only really need to use xsl:element if you want dynamic element names (like shown above), otherwise just output the element directly.
Also, in many cases, all you are doing is converting an upper-case name to lower case. It might be simpler to have a generic template for this
This would cut down on the code you would need to write. You would only need specific templates when you wanted to change element names to something totally different.
Try the following XSLT
When applied to your sample XML, the following is output