I have an XML file that needs some corrections in its structure. Because of the size of said document this has to be done automatically.
The basic structure is the following:
<body>
<div author='author1'>
<lb n='1'/>Text1
<lb n='2'/>Text2
</div>
<lb n='3'/>Text3
<lb n='4'/>Text4
<div author='author1'>
<lb n='5'/>Text5
</div>
<add>xyz</add>
<lb n='6'/>Text6
<lb n='7'/>Text7
<lb n='8'/>Text8
</body>
What I want to do is to put everything that isn't already in div
tags into div
tags and mark it with the attribute @author='author2'
. The text and structure of the moved chunks should stay as it is, just nested into a div
. The order has to be conserved as well.
The resulting XML should look something like this:
<body>
<div author='author1'>
<lb n='1'/>Text1
<lb n='2'/>Text2
</div>
<div author='author2'>
<lb n='3'/>Text3
<lb n='4'/>Text4
</div>
<div author='author1'>
<lb n='5'/>Text5
</div>
<div author='author2'>
<add>xyz</add>
<lb n='6'/>Text6
<lb n='7'/>Text7
<lb n='8'/>Text8
</div>
</body>
My current XSLT (which I wrote before noticing that the XML has more elements than just lb
) does put lb
in the correct div
, but it moves everything to the bottom and deletes the text.
The XSLT looks like this:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xd="http://www.oxygenxml.com/ns/doc/xsl" version="2.0">
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="body">
<xsl:copy>
<xsl:apply-templates select="*[not(self::lb)]"/>
<div>
<xsl:attribute name="resp">author2</xsl:attribute>
<xsl:apply-templates select="lb"/>
</div>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
And it returns this XML:
<?xml version="1.0"?>
<body><div author="author1">
<lb n="1"/>Text1
<lb n="2"/>Text2
</div><div author="author1">
<lb n="5"/>Text5
</div><add>xyz</add><div resp="author2"><lb n="3"/><lb n="4"/><lb n="6"/><lb n="7"/><lb n="8"/></div></body>
What am I doing wrong?
Thanks for your help in advance!
As an alternative to using group-adjacent
, you could use group-starting-with
on the xsl:for-each-group
Try this XSLT
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.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="body">
<xsl:copy>
<xsl:for-each-group select="node()" group-starting-with="div">
<xsl:apply-templates select="." />
<xsl:if test="current-group()[2]">
<div resp="author2">
<xsl:apply-templates select="current-group()[position() gt 1]"/>
</div>
</xsl:if>
</xsl:for-each-group>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>