Reputation: 53
The feedback from my previous post worked a charm but I have encountered the following with some of the documents on our system. The output is as below.
<par def='1'>
<run>This is start of line one para one </run>
<run>text hotspot 1</run>
<run> remainder of line one<break/></run>
<run>This is line 2 </run>
<run>another hotspot </run>
<run>remainder of line 2 <break/></run>
</par>
Is it possible to generate the following output using XSLT?
<document>
<para>This is start of line one para one text hotspot 1 remainder of line one</para>
<para>This is line 2 another hotspot remainder of line 2</para>
</document>
ie, the <break/>
node indicates the end of a sentence but a sentence may run over several <run>
nodes.
In case anyone is wondering, the source data is generated from Lotus Notes in it's DXL schema format.
I have been using a 3rd party tool to generate my XSLT to date, I'm happy to provide the code but it's not very clean.
Thank you again in advance, becoming a huge fan of this forum.
Dono
Upvotes: 2
Views: 120
Reputation: 549
Though isn't a preferable method it works your way..
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="par">
<document>
<para>
<xsl:apply-templates select="node()"/>
</para>
</document>
</xsl:template>
<xsl:template match="run">
<xsl:value-of select="."/>
<xsl:apply-templates select="break"/>
</xsl:template>
<xsl:template match="break">
<xsl:value-of select="'</para>'" disable-output-escaping="yes"/>
<xsl:value-of select="'<para>'" disable-output-escaping="yes"/>
</xsl:template>
</xsl:stylesheet>
Upvotes: 1
Reputation: 243469
This transformation:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="kPreceding" match="run"
use="generate-id((following::break|descendant::break)[1])"/>
<xsl:template match="par">
<document>
<xsl:apply-templates select="run/break"/>
</document>
</xsl:template>
<xsl:template match="break">
<para><xsl:apply-templates select="key('kPreceding', generate-id())/text()"/></para>
</xsl:template>
</xsl:stylesheet>
when applied on the provided XML document:
<par def='1'>
<run>This is start of line one para one </run>
<run>text hotspot 1</run>
<run> remainder of line one<break/></run>
<run>This is line 2 </run>
<run>another hotspot </run>
<run>remainder of line 2<break/></run>
</par>
produces the wanted, correct result:
<document>
<para>This is start of line one para one text hotspot 1 remainder of line one</para>
<para>This is line 2 another hotspot remainder of line 2</para>
</document>
Explanation:
This is a typical XSLT 1.0 positional grouping solution. We use a key to express the relationship between a break
element and all the run
elements which it identifies as a group.
Upvotes: 0
Reputation: 15371
What about this? It only creates new <para>
elements for the first <run>
in a <par>
and if the immediately preceding <par>
has a <break>
in it.
<xsl:template match="par">
<xsl:for-each select="run[preceding-sibling::run[1]/break or not(preceding-sibling::run)]">
<para>
<xsl:apply-templates select="."/>
</para>
</xsl:for-each>
</xsl:template>
<xsl:template match="run">
<xsl:value-of select="."/>
<xsl:if test="not(break)">
<xsl:apply-templates select="following-sibling::run[1]"/>
</xsl:if>
</xsl:template>
Upvotes: 1