thebaz Posted October 21, 2011 Share Posted October 21, 2011 I am really new to XSLT; I started yesterday evening and transformed some very basic file. Now I am working on real-world example and having a problem. I am using a XML file produced by a famous desktop publishing application (Adobe InDesign) and its structure is something I am defining a "flat structure". Here is a example: <?xml version="1.0" encoding="UTF-8"?><Root> <service></service> <description></description> <description></description> <description></description> <service></service> <description></description> <description></description> <service></service> <description></description></Root> While transforming it I have to iterate to within each item because the expected result should be: <?xml version="1.0" encoding="UTF-8"?><Root> <service> <description></description> <description></description> <description></description> </service> <service> <description></description> <description></description> </service> <service> <description></description> </service></Root> Is there any way to reach this goal? Any help would be very appreciated --baz Link to comment Share on other sites More sharing options...
Martin Honnen Posted October 21, 2011 Share Posted October 21, 2011 With XSLT 2.0 (as supported by XSLT 2.0 processors like Saxon 9 or AltovaXML) you can simply do <xsl:output indent="yes"/> <xsl:template match="Root"> <xsl:copy> <xsl:for-each-group select="*" group-starting-with="service"> <service> <xsl:copy-of select="current-group() except ."/> </service> </xsl:for-each-group> </xsl:copy></xsl:template> With XSLT 1.0 you could process all service elements and key the other elements on their service sibling <xsl:output indent="yes"/> <xsl:key name="k1" match="Root/*[not(self::service)]" use="generate-id(preceding-sibling::service[1])"/> <xsl:template match="Root"> <xsl:copy> <xsl:apply-templates select="service"/> </xsl:copy></xsl:template> <xsl:template match="service"> <xsl:copy> <xsl:copy-of select="key('k1', generate-id())"/> </xsl:copy></xsl:template> Untested code typed directly here in the forum editor but it should give you an idea. Link to comment Share on other sites More sharing options...
thebaz Posted October 21, 2011 Author Share Posted October 21, 2011 Hello Martin, thank you very much. I can't use version 2.0 but your code for 1.0 is great for me. BTW, I still need your help: can you help me in understanding the way it works? --Baz Link to comment Share on other sites More sharing options...
Martin Honnen Posted October 22, 2011 Share Posted October 22, 2011 The stylesheet makes a shallow copy of the "Root" element and then processes all "service" child elements of the "Root" element. The template for the "service" elements again makes a shallow copy of each service element and populates it by making a deep copy of the result of calling key('k1', generate-id()). With the "k1" key definition being <xsl:key name="k1" match="Root/*[not(self::service)]" use="generate-id(preceding-sibling::service[1])"/> we have instructed the XSLT processor to index all child elements of the Root element (Root/*) which are not "service" elements ([not(self::service)]) with the generated id of the first preceding sibling service element. With that definition of the key "k1" the call "key('k1', generate-id())" where the context node is a "service" elements returns a node-set of all element that have that "service" element as the first preceding sibling service element. So that way we can wrap all those elements into a service element in the transformation result.That is a rough description but if you are not familiar with XSLT specifics like keys there are lots of tutorials and books you can consult to get a better understanding. Link to comment Share on other sites More sharing options...
thebaz Posted October 26, 2011 Author Share Posted October 26, 2011 Martin, thank you so much. --Baz Link to comment Share on other sites More sharing options...
Recommended Posts
Archived
This topic is now archived and is closed to further replies.