2

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

1
  • 2
    XSLT 1.0 or 2.0? In 2.0 it's very easy, using <xsl:for-each-group select="run" group-ending-with="run[break]">. Commented Dec 6, 2012 at 11:25

3 Answers 3

1

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>
Sign up to request clarification or add additional context in comments.

Comments

1

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="'&#60;/para&#62;'" disable-output-escaping="yes"/>
    <xsl:value-of select="'&#60;para&#62;'" disable-output-escaping="yes"/>
  </xsl:template>
</xsl:stylesheet>

2 Comments

You should only consider disable-output-escaping as an absolute last resort when there's no other way to achieve what you're after. It's not supported by all processors, and won't work if you're using an API to produce output as a DOM tree in memory rather than a file on disk, for example.
@IanRoberts, I tried an alternative to the existing one! Since existing answer had it at its best I tried a robust way .. which is ofcourse not preferred .. And not advised :)
0

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.