Reputation: 569
Seen lots of similar questions here on StackOverflow, and I've been trying to follow those all day to get my specific situation figured out, but little luck.
I want to take this xml:
<RestaurantData>
<Foodie>
<Id>123</Id>
<Name>Bob</Name>
<Restaurants>
<Restaurant>
<Name>Noma</Name>
<TimesEaten>12</TimesEaten>
</Restaurant>
<Restaurant>
<Name>Eleven Madison Park</Name>
<TimesEaten>15</TimesEaten>
</Restaurant>
<Restaurant>
<Name>Mugaritz</Name>
<TimesEaten>15</TimesEaten>
</Restaurant>
</Restaurants>
</Foodie>
<Foodie>
<Id>789</Id>
<Name>Charlie</Name>
<Restaurants>
<Restaurant>
<Name>Noma</Name>
<TimesEaten>1</TimesEaten>
</Restaurant>
<Restaurant>
<Name>Eleven Madison Park</Name>
<TimesEaten>125</TimesEaten>
</Restaurant>
</Restaurants>
</Foodie>
</RestaurantData>
and apply an XSLT to get this:
<RestaurantData>
<Foodie>
<Id>123</Id>
<Name>Bob</Name>
<Noma>12</Noma>
<Eleven-Madison-Park>15</Eleven-Madison-Park>
<Mugaritz>15</Mugaritz>
</Foodie>
<Foodie>
<Id>789</Id>
<Name>Charlie</Name>
<Noma>1</Noma>
<Eleven-Madison-Park>125</Eleven-Madison-Park>
</Foodie>
</RestaurantData>
The closest I've come to my XSLT is this, and the results are not very close at all to the above:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:my="my:my" exclude-result-prefixes="my" >
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*[ancestor::Restaurant]">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="text()[ancestor::Restaurant]">
<xsl:value-of select="normalize-space()"/>
</xsl:template>
</xsl:stylesheet>
Any help would be greatly appreciated.
Upvotes: 0
Views: 128
Reputation: 23627
Replace your second and third templates with these two:
<xsl:template match="Restaurants">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="Restaurant">
<xsl:element name="{translate(Name,' ','-')}">
<xsl:value-of select="TimesEaten"/>
</xsl:element>
</xsl:template>
The first one flattens the Restaurants
tree. The second flattens each Restaurant
tree replacing their children for one element. The {}
are Attribute Value Templates that allow XPath expressions inside common attributes. The translate()
function replaces spaces with dashes so that the name is generated correctly.
You should be aware that, depending on the names of your restaurants, the transformation may fail due to invalid tag names. Besides replacing the spaces, you should check for other situations that might generate illegal QNames for your tags, such as apostrophes, names that start with numbers, empty-strings, etc. In XML you can't have tags like <Charlie's>
or <5th Ave.>
, and replacing them might be tricky (at least in XSLT 1.0).
To convert Charlie's
into Charlie-s
, for example, you can create a variable to store the '
:
<xsl:variable name="apos">'</xsl:variable>
and add the replacement to the translate
:
translate(Name,concat(' ',$apos),'--')
For words starting with numbers, in XSLT 2.0 you could use replace()
and regular expressions, but in XSLT 1.0 you will need to check for digits at the beginning of each name.
Upvotes: 1