I am looking to parse a set of comma delimited image URLs for real estate data within a single xml tag and write them out as separate tags. This is way beyond my current knowledge and I am having real trouble learning what I need to do quickly enough to get this job done. If someone could help, it would be much appreciated.
Here is the XML:
<Report>
<Row1>
<Reference>001</Reference>
<Type>House</Type>
<Location>New York</Estado>
<Size>665.6</Size>
<Images>http://www.example.com/001/image1.jpg,http://www.example.com/001/image2.jpg,http://www.example.com/001/image3.jpg,http://www.example.com/001/image4.jpg</Images>
</Row1>
<Row2>
<Reference>056</Reference>
<Type>Apartment</Type>
<Location>Washington</Estado>
<Size>147.5</Size>
<Images>http://www.example.com/056/image1.jpg,http://www.example.com/056/image5.jpg,http://www.example.com/056/image8.jpg,http://www.example.com/056/image9.jpg</Images>
</Row2>
</Report>
This is what I would like to output:
<RESULTSET>
<ROW>
<COL><DATA>001</DATA></COL>
<COL><DATA>House</DATA></COL>
<COL><DATA>New York</DATA></COL>
<COL><DATA>665.6</DATA></COL>
<COL><DATA>http://www.example.com/001/image1.jpg</DATA></COL>
<COL><DATA>http://www.example.com/001/image2.jpg</DATA></COL>
<COL><DATA>http://www.example.com/001/image3.jpg</DATA></COL>
<COL><DATA>http://www.example.com/001/image4.jpg</DATA></COL>
</ROW>
<ROW>
<COL><DATA>056</DATA></COL>
<COL><DATA>Apartment</DATA></COL>
<COL><DATA>Washington</DATA></COL>
<COL><DATA>147.5</DATA></COL>
<COL><DATA>http://www.example.com/056/image1.jpg</DATA></COL>
<COL><DATA>http://www.example.com/056/image5.jpg</DATA></COL>
<COL><DATA>http://www.example.com/056/image8.jpg</DATA></COL>
<COL><DATA>http://www.example.com/056/image9.jpg</DATA></COL>
</ROW>
</RESULTSET>
Thank you for any help you can give me.
All source nodes, except for the Images
nodes, can be processed by simple templates that extract their content and reorganize it in your new structure:
<xsl:template match="Report">
<RESULTSET>
<xsl:apply-templates/>
</RESULTSET>
</xsl:template>
<xsl:template match="Report/*">
<ROW>
<xsl:apply-templates/>
</ROW>
</xsl:template>
<xsl:template match="Report/*/*[not(self::Images)]">
<COL><DATA>
<xsl:value-of select="."/>
</DATA></COL>
</xsl:template>
The Images
node requires splitting the string by a separator (,
). To achieve this in XSLT 1.0 you need a named template that you can call recursively. It will be called by a template that matches the Images
element:
<xsl:template match="Images">
<xsl:call-template name="split">
<xsl:with-param name="string" select="."/>
</xsl:call-template>
</xsl:template>
The named template split
checks if there is a comma in the sequence. If not, it simply returns the contents wrapped in a <COL><DATA>
block. If there is, the first element is extracted and the rest of the string is processed by the same template recursively, until all items are processed. The result will be a list of <COL><DATA>
blocks each containing one item:
<xsl:template name="split">
<xsl:param name="string"/>
<xsl:param name="separator">,</xsl:param>
<xsl:choose>
<xsl:when test="contains($string, $separator)">
<xsl:variable name="first-string" select="substring-before($string, $separator)"/>
<xsl:variable name="rest" select="substring-after($string, concat($first-string,$separator))"/>
<COL><DATA><xsl:value-of select="$first-string"/></DATA></COL>
<xsl:call-template name="split">
<xsl:with-param name="string" select="$rest"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<COL><DATA><xsl:value-of select="$string"/></DATA></COL>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
You can try it out in this XSLT Fiddle