Reputation: 815
I have a large XML file which is structured like this:
<text n="1">
<front>
<title n="t1-1">A</title>
<title n="t1-2">B</title>
</front>
<body>
<p>
<seg n="1-1">some <add>foo</add> text</seg>
<seg n="1-2">some <add>foo</add> <add>foo</add> text</seg>
<seg n="1-3">some <add>foo</add> text</seg>
</p>
</body>
</text>
<text n="2">
<front>
<title n="t2-1">X</title>
<title n="t2-2">Y</title>
</front>
<body>
<p>
<seg n="2-1">some <add>foo</add> text</seg>
<seg n="2-2">some <add>foo</add> text</seg>
<seg n="2-3">some text</seg>
</p>
</body>
</text>
<text>
.....
</text>
I would like to transform it into a new XML document structured like this:
<document>
<p n="1">
<newtitle>A B</title>
<seg n="1-1">some text</seg>
<seg n="1-2">some text</seg>
<seg n="1-3">some text</seg>
<adds>
<add>foo</add>
<add>foo</add>
<add>foo</add>
<add>foo</add>
</adds>
</p>
<p n="2">
<newtitle>X Y</title>
<seg n="2-1">some text</seg>
<seg n="2-2">some text</seg>
<seg n="2-3">some text</seg>
<adds>
<add>foo</add>
<add>foo</add>
</adds>
</p>
<p>
....
</p>
</document>
I've tried several attempts using identity transform withxsl:for-each
, but can't get it to extract and rearrange correctly.
Thanks in advance for any assistance.
Upvotes: 0
Views: 28
Reputation: 167516
Here is an XSLT 3 solution (for XSLT 2 you need to spell out <xsl:mode on-no-match="shallow-copy"/>
with the identity transformation template instead):
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs"
version="3.0">
<xsl:mode on-no-match="shallow-copy"/>
<xsl:strip-space elements="*"/>
<xsl:output indent="yes"/>
<xsl:template match="root">
<document>
<xsl:apply-templates/>
</document>
</xsl:template>
<xsl:template match="text">
<p>
<xsl:apply-templates select="@* | node()"/>
</p>
</xsl:template>
<xsl:template match="text/front">
<newtitle>
<xsl:value-of select="title"/>
</newtitle>
</xsl:template>
<xsl:template match="text/body">
<xsl:apply-templates select="p/seg"/>
<adds>
<xsl:apply-templates select="p/seg/add"/>
</adds>
</xsl:template>
<xsl:template match="text/body/p/seg">
<xsl:copy>
<xsl:apply-templates select="@* | text()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
As you can see, by breaking up the task into template to transform each node into its target you get a well-structured approach.
Online sample at http://xsltfiddle.liberty-development.net/nbUY4kh/2
Upvotes: 1