I've been tasked with tidying up some XML so despite a rather loose DTD, everything is declared in the same way. For example, in the elements below
<all>
<e>
<hg>
<hw>things</hw>
<posg><pos value="abc" /></posg>
</hg>
<sg><se1 /></sg>
</e>
<e>
<hg>
<hw>stuff</hw>
<posg><pos value="def" /></posg>
</hg>
<sg>
<se1>
<posg><pos value="ghi" /></posg>
</se1>
</sg>
</e>
</all>
the <posg>
element should be a child of <se1>
and not <hg>
. Furthermore, if a <posg>
element already exists in the <se1>
element, then I should create a new <se1>
element as the first child of <sg>
and then move the <posg>
element from <hg>
to the new <se1>
element.
In effect then, the two elements above should look like this after transformation
<all>
<e>
<hg>
<hw>things</hw>
</hg>
<sg>
<se1>
<posg><pos value="abc" /></posg>
</se1>
</sg>
</e>
<e>
<hg>
<hw>stuff</hw>
</hg>
<sg>
<se1>
<posg><pos value="def" /></posg>
</se1>
<se1>
<posg><pos value="ghi" /></posg>
</se1>
</sg>
</e>
</all>
I have been struggling with how to check whether the rogue <posg>
element exists within <hg>
and then take the appropriate action described above.
Use the following script:
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" omit-xml-declaration="yes" encoding="UTF-8" indent="yes" />
<xsl:strip-space elements="*"/>
<xsl:template match="sg">
<xsl:copy>
<xsl:if test="../hg/posg">
<se1><xsl:copy-of select="../hg/posg"/></se1>
</xsl:if>
<xsl:if test="se1/posg">
<xsl:apply-templates select="@*|node()"/>
</xsl:if>
</xsl:copy>
</xsl:template>
<xsl:template match="hg/posg"/>
<xsl:template match="@*|node()">
<xsl:copy><xsl:apply-templates select="@*|node()"/></xsl:copy>
</xsl:template>
</xsl:transform>