Reputation: 535
I need to move the copy the parent node into multiple children nodes, WITHOUT copying said children itself in the process. Here's an example XML:
<FoodGroups>
<Nutritional>Yes</Nutritional>
<Artifical>No</Artificial>
<FoodGroup>
<Fruit>Grape</Fruit>
<Fruit>Apple</Fruit>
</FoodGroup>
<FoodGroup>
<Vegetable>Carrot</Vegetable>
<Vegetable>Potato</Vegetable>
<FoodGroup>
</FoodGroups>
When the transformation finishes, I need the XML to look like this:
<xml>
<FoodGroup>
<Fruit>Grape</Fruit>
<Fruit>Apple</Fruit>
<FoodGroups>
<Nutritional>Yes</Nutritional>
<Articial>No</Artificial>
</FoodGroups>
</FoodGroup>
<FoodGroup>
<Vegetable>Carrot</Vegetable>
<Vegetable>Potato</Vegetable>
<FoodGroups>
<Nutritional>Yes</Nutritional>
<Articial>No</Artificial>
</FoodGroups>
<FoodGroup>
</xml>
I've tried using the following XML:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt"
exclude-result-prefixes="msxsl">
<xsl:output omit-xml-declaration="yes"
method="xml"
indent="yes"/>
<xsl:template match="/">
<xml>
<xsl:copy>
<xsl:apply-templates select="//FoodGroup"/>
</xsl:copy>
</xml>
</xsl:template>
<xsl:template match="//FoodGroup">
<FoodGroup>
<xsl:copy-of select="./*"/>
<xsl:copy-of select="//FoodGroups/*[not(child::FoodGroup)]"/>
</FoodGroup>
</xsl:template>
</xsl:stylesheet>
However, I get the following output (the children nodes COMPLETELY re-copy - I don't want this):
<xml>
<FoodGroup>
<Fruit>Grape</Fruit>
<Fruit>Apple</Fruit>
<FoodGroups>
<Nutritional>Yes</Nutritional>
<Artifical>No</Artificial>
<FoodGroup>
<Fruit>Grape</Fruit>
<Fruit>Apple</Fruit>
</FoodGroup>
<FoodGroup>
<Vegetable>Carrot</Vegetable>
<Vegetable>Potato</Vegetable>
<FoodGroup>
</FoodGroups>
</FoodGroup>
<FoodGroup>
<Vegetable>Carrot</Vegetable>
<Vegetable>Potato</Vegetable>
<FoodGroups>
<Nutritional>Yes</Nutritional>
<Artifical>No</Artificial>
<FoodGroup>
<Fruit>Grape</Fruit>
<Fruit>Apple</Fruit>
</FoodGroup>
<FoodGroup>
<Vegetable>Carrot</Vegetable>
<Vegetable>Potato</Vegetable>
<FoodGroup>
</FoodGroups>
<FoodGroup>
</xml>
Can this kind of parent to children copying be done? Is it possible? Part of the difficulty is that sometimes these children are more than one level deep.
Upvotes: 0
Views: 47
Reputation: 116972
Why not simply (and also more efficiently):
XSLT 1.0
<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="/FoodGroups">
<xml>
<xsl:variable name="common" select="*[not(self::FoodGroup)]" />
<xsl:for-each select="FoodGroup">
<xsl:copy>
<xsl:copy-of select="*"/>
<FoodGroups>
<xsl:copy-of select="$common"/>
</FoodGroups>
</xsl:copy>
</xsl:for-each>
</xml>
</xsl:template>
</xsl:stylesheet>
Upvotes: 0
Reputation: 167471
The following seems to do the job:
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output method="xml" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/">
<xml>
<xsl:apply-templates/>
</xml>
</xsl:template>
<xsl:template match="FoodGroups">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="FoodGroups/*[not(self::FoodGroup)]"/>
<xsl:template match="FoodGroup">
<xsl:copy>
<xsl:apply-templates/>
<FoodGroups>
<xsl:copy-of select="ancestor::FoodGroups/*[not(self::FoodGroup)]"/>
</FoodGroups>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Upvotes: 0