Help needed with transition

H

Hvid Hat

Hi

Can anyone help me with the following transition? My problem is how to create
a fieldset each time I run into a heading and then include the following text
elements within the fieldset.

<?xml version="1.0" encoding="ISO-8859-1"?>
<field>
<heading>First heading</heading>
</field>
<field>
<text>Lorem</text>
</field>
<field>
<text>Ipsum</text>
</field>
<field>
<heading>Second heading</heading>
</field>
<field>
<text>Dolor</text>
</field>
<field>
<text>Sit</text>
</field>
<field>
<heading>Third heading</heading>
</field>
<field>
<text>Amet</text>
</field>

To

<fieldset>
<legend>First heading</legend>
<p>Lorem</p>
<p>Ipsum</p>
</fieldset>
<fieldset>
<legend>Second heading</legend>
<p>Dolor</p>
<p>Sit</p>
</fieldset>
<fieldset>
<legend>Third heading</legend>
<p>Amet</p>
</fieldset>
 
H

Hvid Hat

I'm getting closer but still no cigar :-(

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:template match="/">
<xsl:apply-templates select="//heading" />
</xsl:template>
<xsl:template match="heading">
<fieldset>
<legend>
<xsl:value-of select="."/>
</legend>
<!-- Only text elements following above heading -->
<xsl:apply-templates select="//text" />
</fieldset>
</xsl:template>
<xsl:template match="text">
<p>
<xsl:value-of select="."/>
</p>
</xsl:template>
</xsl:stylesheet>

Where my comment is in the XSLT above I need help. I've looked at
following-sibling which could be what I need but I can't figure out how...
anyone?
 
D

David Carlisle

Hvid said:
Hi

Can anyone help me with the following transition? My problem is how to create
a fieldset each time I run into a heading and then include the following text
elements within the fieldset.


Don't think of it that way it will lead to pain, xslt doesn't assume a
processing order so it is hard to say stop one fieldset and start
another when you see a heading. Instead give a global description: you
want to group all the fields in order, with groups starting at each
heading. the XSLT2 version follws immediately from this, and teh XSLT 1
version is a standard rewriting of that to the muenchian grouping idiom,
which looks a bit srange but google will show dozens of examples.



<x>
<field>
<heading>First heading</heading>
</field>
<field>
<text>Lorem</text>
</field>
<field>
<text>Ipsum</text>
</field>
<field>
<heading>Second heading</heading>
</field>
<field>
<text>Dolor</text>
</field>
<field>
<text>Sit</text>
</field>
<field>
<heading>Third heading</heading>
</field>
<field>
<text>Amet</text>
</field>
</x>


<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:strip-space elements="*"/>
<xsl:eek:utput indent="yes"/>

<xsl:template match="x">
<xsl:for-each-group select="field" group-starting-with="field
">
<fieldset>
<xsl:apply-templates select="current-group()"/>
</fieldset>
</xsl:for-each-group>
</xsl:template>

<xsl:template match="heading">
<legend><xsl:value-of select="."/></legend>
</xsl:template>

<xsl:template match="text">
<p><xsl:value-of select="."/></p>
</xsl:template>

</xsl:stylesheet>



or if you are still using xslt1:


<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:strip-space elements="*"/>
<xsl:eek:utput indent="yes"/>

<xsl:key name="f" match="text"
use="(../preceding-sibling::field/heading)[last()]"/>

<xsl:template match="x">
<xsl:for-each select="field/heading">
<fieldset>
<xsl:apply-templates select=".|key('f',.)"/>
</fieldset>
</xsl:for-each>
</xsl:template>

<xsl:template match="heading">
<legend><xsl:value-of select="."/></legend>
</xsl:template>

<xsl:template match="text">
<p><xsl:value-of select="."/></p>
</xsl:template>

</xsl:stylesheet>



<?xml version="1.0" encoding="ISO-8859-1"?>
<field>
<heading>First heading</heading>
</field>
<field>

That input isn't well formed so I put in a surrounding x element​
 
D

David Carlisle

Hvid said:
Hi

Can anyone help me with the following transition? My problem is how to create
a fieldset each time I run into a heading and then include the following text
elements within the fieldset.


Don't think of it that way it will lead to pain, xslt doesn't assume a
processing order so it is hard to say stop one fieldset and start
another when you see a heading. Instead give a global description: you
want to group all the fields in order, with groups starting at each
heading. the XSLT2 version follws immediately from this, and teh XSLT 1
version is a standard rewriting of that to the muenchian grouping idiom,
which looks a bit srange but google will show dozens of examples.



<x>
<field>
<heading>First heading</heading>
</field>
<field>
<text>Lorem</text>
</field>
<field>
<text>Ipsum</text>
</field>
<field>
<heading>Second heading</heading>
</field>
<field>
<text>Dolor</text>
</field>
<field>
<text>Sit</text>
</field>
<field>
<heading>Third heading</heading>
</field>
<field>
<text>Amet</text>
</field>
</x>


<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:strip-space elements="*"/>
<xsl:eek:utput indent="yes"/>

<xsl:template match="x">
<xsl:for-each-group select="field" group-starting-with="field
">
<fieldset>
<xsl:apply-templates select="current-group()"/>
</fieldset>
</xsl:for-each-group>
</xsl:template>

<xsl:template match="heading">
<legend><xsl:value-of select="."/></legend>
</xsl:template>

<xsl:template match="text">
<p><xsl:value-of select="."/></p>
</xsl:template>

</xsl:stylesheet>



or if you are still using xslt1:


<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:strip-space elements="*"/>
<xsl:eek:utput indent="yes"/>

<xsl:key name="f" match="text"
use="(../preceding-sibling::field/heading)[last()]"/>

<xsl:template match="x">
<xsl:for-each select="field/heading">
<fieldset>
<xsl:apply-templates select=".|key('f',.)"/>
</fieldset>
</xsl:for-each>
</xsl:template>

<xsl:template match="heading">
<legend><xsl:value-of select="."/></legend>
</xsl:template>

<xsl:template match="text">
<p><xsl:value-of select="."/></p>
</xsl:template>

</xsl:stylesheet>



<?xml version="1.0" encoding="ISO-8859-1"?>
<field>
<heading>First heading</heading>
</field>
<field>

That input isn't well formed so I put in a surrounding x element​
 
M

Mukul Gandhi

David has given both a 2.0 and a 1.0 solution. I wouldn't write
anything different for what David wrote for XSLT 2.0.

But here's a slightly different 1.0 solution,

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">

<xsl:eek:utput method="xml" indent="yes" />

<xsl:template match="x">
<result>
<xsl:apply-templates select="field
" mode="a" />
</result>
</xsl:template>

<xsl:template match="field" mode="a">
<fieldset>
<legend><xsl:value-of select="heading" /></legend>
<xsl:apply-templates select="following-sibling::field[1][text]"
mode="b" />
</fieldset>
</xsl:template>

<xsl:template match="field" mode="b">
<p><xsl:value-of select="text" /></p>
<xsl:apply-templates select="following-sibling::field[1][text]"
mode="b" />
</xsl:template>

</xsl:stylesheet>

this is popularly known as the sibling recursion technique.

Cheers,
Mukul​
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,774
Messages
2,569,596
Members
45,141
Latest member
BlissKeto
Top