Reputation: 8706
I'm trying to transform old XML files into a new and improved structure. Part of this needs me to wrap some loose elements into a parent container, as well as modify their children
Old structure
<monograph>
<title>asdf</title>
<dosage.sec id="dosage.sec.1">
<dosage.sec>asgfd</dosage.sec>
<dosage.sec>asgfd</dosage.sec>
</dosage.sec>
<dosage.sec id="dosage.sec.2">
<dosage.sec>asgfd</dosage.sec>
<dosage.sec>asgfd</dosage.sec>
</dosage.sec>
<dosage.sec id="dosage.sec.3">
<dosage.sec>asgfd</dosage.sec>
<dosage.sec>asgfd</dosage.sec>
</dosage.sec>
<products>
<prod>sadf</prod>
<prod>sadf</prod>
</products>
</monograph>
New structure
<monograph>
<title>asdf</title>
<dosage>
<dosage.sec id="dosage.sec.1">
<dosage.qual>asgfd</dosage.qual>
<dosage.qual>asgfd</dosage.qual>
</dosage.sec>
<dosage.sec id="dosage.sec.2">
<dosage.qual>asgfd</dosage.qual>
<dosage.qual>asgfd</dosage.qual>
</dosage.sec>
<dosage.sec id="dosage.sec.3">
<dosage.qual>asgfd</dosage.qual>
<dosage.qual>asgfd</dosage.qual>
</dosage.sec>
</dosage>
<products>
<prod>sadf</prod>
<prod>sadf</prod>
</products>
</monograph>
I found this answer and modified it a bit to suit my needs:
<!-- wrap dosage.sec elements in a dosage container -->
<xsl:template match="node()|@*" name="dosage.sec">
<xsl:copy>
<xsl:apply-templates select="node()|@*" />
</xsl:copy>
</xsl:template>
<xsl:template match="monograph/dosage.sec[not(preceding-sibling::*[1][self::dosage.sec])]">
<dosage>
<xsl:call-template name="dosage.sec" />
<xsl:apply-templates mode="copy" select="following-sibling::*[1][self::dosage.sec]" />
</dosage>
</xsl:template>
<xsl:template match="monograph/dosage.sec" mode="copy">
<xsl:call-template name="dosage.sec"/>
</xsl:template>
<!-- rename children dosage.sec -->
<xsl:template match="dosage.sec/dosage.sec">
<dosage.qual>
<xsl:apply-templates />
</dosage.qual>
</xsl:template>
But my output is:
<monograph>
<title>asdf</title>
<dosage>
<dosage.sec id="dosage.sec.1">
<dosage.qual>asgfd</dosage.qual>
<dosage.qual>asgfd</dosage.qual>
</dosage.sec>
<dosage.sec id="dosage.sec.2">
<dosage.qual>asgfd</dosage.qual>
<dosage.qual>asgfd</dosage.qual>
</dosage.sec>
<dosage.sec id="dosage.sec.3">
<dosage.qual>asgfd</dosage.qual>
<dosage.qual>asgfd</dosage.qual>
</dosage.sec>
</dosage>
<dosage.sec id="dosage.sec.3">
<dosage.qual>asgfd</dosage.qual>
<dosage.qual>asgfd</dosage.qual>
</dosage.sec>
<products>
<prod>sadf</prod>
<prod>sadf</prod>
</products>
</monograph>
I'm using PHP5's built-in XSLTProcessor object - all XML and XSL are version 1.0
Upvotes: 0
Views: 404
Reputation: 8706
I had a few other problems on the way - for one, I discovered that the dosage.sec elements were not in contiguous block and I was erroneously creating two dosage containers.
These templates solved my problems:
<!-- wrap dosage.sec elements in a dosage container -->
<xsl:template match="monograph/dosage.sec" name="dosage.sec">
<xsl:param name="drugname" />
<xsl:copy>
<xsl:apply-templates>
<xsl:with-param name="drugname" select="$drugname" />
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
<xsl:template match="monograph/dosage.sec[not(preceding::dosage.sec)]">
<xsl:param name="drugname" />
<dosage>
<xsl:call-template name="dosage.sec">
<xsl:with-param name="drugname" select="$drugname" />
</xsl:call-template>
<xsl:apply-templates mode="copy" select="following::dosage.sec">
<xsl:with-param name="drugname" select="$drugname" />
</xsl:apply-templates>
</dosage>
</xsl:template>
<xsl:template match="monograph/dosage.sec" mode="copy">
<xsl:param name="drugname" />
<xsl:call-template name="dosage.sec">
<xsl:with-param name="drugname" select="$drugname" />
</xsl:call-template>
</xsl:template>
<xsl:template match="monograph/dosage.sec[(preceding::dosage.sec)]" />
Upvotes: 0
Reputation: 101700
How about this:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="monograph">
<xsl:copy>
<dosage>
<xsl:apply-templates select="@* | node()" />
</dosage>
</xsl:copy>
</xsl:template>
<!-- rename children dosage.sec -->
<xsl:template match="dosage.sec/dosage.sec">
<dosage.qual>
<xsl:apply-templates />
</dosage.qual>
</xsl:template>
</xsl:stylesheet>
When run on your sample input, this produces:
<monograph>
<dosage>
<dosage.sec>
<dosage.qual>asgfd</dosage.qual>
<dosage.qual>asgfd</dosage.qual>
</dosage.sec>
<dosage.sec>
<dosage.qual>asgfd</dosage.qual>
<dosage.qual>asgfd</dosage.qual>
</dosage.sec>
<dosage.sec>
<dosage.qual>asgfd</dosage.qual>
<dosage.qual>asgfd</dosage.qual>
</dosage.sec>
</dosage>
</monograph>
Upvotes: 2