473,413 Members | 1,798 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,413 software developers and data experts.

XSLT - Sub-grouping in mixed nodes

MRe
Hi,

Is it possible using XSLT to transform this..

<test>
<b>0</b>
<a>1</a>
<a>2</a>
<b>3</b>
<b>4</b>
5
<b>6</b>
<b>7</b>
<b>8</b>
</test>

..into this (it's basically just wrapping groups of <b>s in a <c>)..

<test>
<c>
<b>0</b>
</c>
<a>1</a>
<a>2</a>
<c>
<b>3</b>
<b>4</b>
</c>
5
<c>
<b>6</b>
<b>7</b>
<b>8</b>
</c>
</test>

..that is, treat, in a mix of nodes, a specified group of nodes
(nodes that appear one-after-the-other, having no node outside that
group (except ignored empty text() nodes) between them) as a block?
(in the example above, <bis the only chosen node in this group)

The closest I've come to getting this is to call a recursive
template, passing child::*[1] initially, and following-sibling::*[1]
for each recursive step, and also passing a 'block' parameter that, if
false and <bis encountered, puts a <cin and sets block to true,
and if true and <ais encountered, puts a </cin and sets to false.
However, this won't work as it won't put a </cin if the last element
is a <b>.

All other attempts I've made at a solution I'd prefer to keep to
myself [embarrassed]

Thank you,
Kind regards,
Eliott
Aug 14 '08 #1
4 1941
MRe wrote:
Is it possible using XSLT to transform this..

<test>
<b>0</b>
<a>1</a>
<a>2</a>
<b>3</b>
<b>4</b>
5
<b>6</b>
<b>7</b>
<b>8</b>
</test>

..into this (it's basically just wrapping groups of <b>s in a <c>)..

<test>
<c>
<b>0</b>
</c>
<a>1</a>
<a>2</a>
<c>
<b>3</b>
<b>4</b>
</c>
5
<c>
<b>6</b>
<b>7</b>
<b>8</b>
</c>
</test>
With XSLT 2.0 (as supported by Saxon http://saxon.sourceforge.net/,
Gestalt http://gestalt.sourceforge.net/, and Altova
http://www.altova.com/altovaxml.html) you can solve that as follows:

<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="/test">
<xsl:copy>
<xsl:for-each-group select="node()"
group-adjacent="boolean(self::b)">
<xsl:choose>
<xsl:when test="current-grouping-key()">
<c>
<xsl:copy-of select="current-group()"/>
</c>
</xsl:when>
<xsl:otherwise>
<xsl:copy-of select="current-group()"/>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each-group>
</xsl:copy>
</xsl:template>

</xsl:stylesheet>
Or do you need an XSLT 1.0 solution?
--

Martin Honnen
http://JavaScript.FAQTs.com/
Aug 14 '08 #2
MRe wrote:
The closest I've come to getting this is to call a recursive
template, passing child::*[1] initially, and following-sibling::*[1]
for each recursive step, and also passing a 'block' parameter that, if
false and <bis encountered, puts a <cin and sets block to true,
and if true and <ais encountered, puts a </cin and sets to false.
However, this won't work as it won't put a </cin if the last element
is a <b>.
With XSLT 1.0 you can solve such problems by processing sibling by
sibling, here is a sample stylesheet:

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

<xsl:output method="xml" indent="yes"/>
<xsl:strip-space elements="*"/>

<xsl:template match="/test">
<xsl:copy>
<xsl:apply-templates select="node()[1]" mode="group"/>
</xsl:copy>
</xsl:template>

<xsl:template match="test/b" mode="group">
<c>
<xsl:copy-of select="."/>
<xsl:apply-templates select="following-sibling::node()[1][self::b]"/>
</c>
<xsl:apply-templates
select="following-sibling::node()[not(self::b)][1]" mode="group"/>
</xsl:template>

<xsl:template match="test/b">
<xsl:copy-of select="."/>
<xsl:apply-templates select="following-sibling::node()[1][self::b]"/>
</xsl:template>

<xsl:template match="test/node()[not(self::b)]" mode="group">
<xsl:copy-of select="."/>
<xsl:apply-templates select="following-sibling::node()[1]"
mode="group"/>
</xsl:template>

</xsl:stylesheet>
--

Martin Honnen
http://JavaScript.FAQTs.com/
Aug 14 '08 #3
MRe
With XSLT 1.0 you can solve such problems by processing sibling by
sibling, here is a sample stylesheet:
Ha, wow, very cool - this works prefect.

Thank you so much,
Plus extra thank you for the working sample,
And sorry for not stating it, XSLT 1.0 was what I needed

Thanks again,
Kind regards,
Eliott
>

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

<xsl:output method="xml" indent="yes"/>
<xsl:strip-space elements="*"/>

<xsl:template match="/test">
<xsl:copy>
<xsl:apply-templates select="node()[1]" mode="group"/>
</xsl:copy>
</xsl:template>

<xsl:template match="test/b" mode="group">
<c>
<xsl:copy-of select="."/>
<xsl:apply-templates select="following-sibling::node()[1][self::b]"/>
</c>
<xsl:apply-templates
select="following-sibling::node()[not(self::b)][1]" mode="group"/>
</xsl:template>

<xsl:template match="test/b">
<xsl:copy-of select="."/>
<xsl:apply-templates select="following-sibling::node()[1][self::b]"/>
</xsl:template>

<xsl:template match="test/node()[not(self::b)]" mode="group">
<xsl:copy-of select="."/>
<xsl:apply-templates select="following-sibling::node()[1]"
mode="group"/>
</xsl:template>

</xsl:stylesheet>

--

Martin Honnen
http://JavaScript.FAQTs.com/
Aug 14 '08 #4
I will offer this solution, which uses just a key and the identity rule:

<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="kAllChildren" match="b" use=
"generate-id(
(preceding-sibling::node()
[not(self::b)][1]
|
parent::*[
*[1][self::b]
]
)
[last()]
)"/>

<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>

<xsl:template match="node()
[not(self::b)
and
following-sibling::node()[1][self::b]
]">
<xsl:copy-of select="."/>
<c>
<xsl:copy-of select="key('kAllChildren', generate-id())"/>
</c>
</xsl:template>

<xsl:template match="*[*[1][self::b]]">
<xsl:copy>
<xsl:copy-of select="@*"/>
<c>
<xsl:copy-of select="key('kAllChildren', generate-id())"/>
</c>
<xsl:apply-templates select="node()"/>
</xsl:copy>
</xsl:template>

<xsl:template match="b"/>
</xsl:stylesheet>

It produces the correct result even with source xml like this:

<test>
<b>0</b>
<a>1</a>
<a>2</a>
<b>3</b>
<b>4</b>
5
<b>6</b>
<b>7</b>
<b>8</b>
9
<d>
<e>10</e>
<b>11</b>
<e>12</e>
<f>13</f>
<b>14</b>
<b>15</b>
16
<b>17</b>
<b>18</b>
<b>19</b>
20
</d>
21
<b>22</b>
23
</test>

Cheers,
Dimitre Novatchev

"Martin Honnen" <ma*******@yahoo.dewrote in message
news:48***********************@newsspool4.arcor-online.net...
MRe wrote:
> The closest I've come to getting this is to call a recursive
template, passing child::*[1] initially, and following-sibling::*[1]
for each recursive step, and also passing a 'block' parameter that, if
false and <bis encountered, puts a <cin and sets block to true,
and if true and <ais encountered, puts a </cin and sets to false.
However, this won't work as it won't put a </cin if the last element
is a <b>.

With XSLT 1.0 you can solve such problems by processing sibling by
sibling, here is a sample stylesheet:

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

<xsl:output method="xml" indent="yes"/>
<xsl:strip-space elements="*"/>

<xsl:template match="/test">
<xsl:copy>
<xsl:apply-templates select="node()[1]" mode="group"/>
</xsl:copy>
</xsl:template>

<xsl:template match="test/b" mode="group">
<c>
<xsl:copy-of select="."/>
<xsl:apply-templates
select="following-sibling::node()[1][self::b]"/>
</c>
<xsl:apply-templates
select="following-sibling::node()[not(self::b)][1]" mode="group"/>
</xsl:template>

<xsl:template match="test/b">
<xsl:copy-of select="."/>
<xsl:apply-templates select="following-sibling::node()[1][self::b]"/>
</xsl:template>

<xsl:template match="test/node()[not(self::b)]" mode="group">
<xsl:copy-of select="."/>
<xsl:apply-templates select="following-sibling::node()[1]"
mode="group"/>
</xsl:template>

</xsl:stylesheet>
--

Martin Honnen
http://JavaScript.FAQTs.com/

Aug 16 '08 #5

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

2
by: Allan Bredahl | last post by:
Hi All I'm trying hard to find out how to transform XML to HTML using XSLT files. I have searched all over for some examples on how to do this, but I have had no succes with any of them. ...
1
by: Wil | last post by:
I'm very new to developing in .NET and even newer to XML. The past few days have been pretty frustrating for me because I'm trying to perform a transform on data in a dataset and it's not working....
12
by: Keith Chadwick | last post by:
I have a fairly hefty XSLT file that for the sake of debugging and clarity I wish to split into some separate sub-templates contained within the same file. The master template calls an...
0
by: Christopher M. Lauer | last post by:
I have done my best to answer this question but can not find the proper set of commands. I would like to transform an xml file (in code behind) and display its output in a specific html tag,...
2
by: darrel | last post by:
On my page right now, I call a function: <%=getMenu()%> in my codebehind, I have the function do an xslt transformation: sub xslt.Transform(doc, xslArg, Response.Output, Nothing) end sub
7
by: One Handed Man \( OHM - Terry Burns \) | last post by:
I've been battling with this stupid problem for hours now. WebApp: Trying to do a simple transformation using XSLT to a Web Page, but it just failes without an error message ( In other words,...
1
by: jrwarwick | last post by:
Hello, I believe I have uncovered a bug in the .Net XSLT engine to do with 'for' loops in XSLT. Here are the steps to reproduce it: -Create A new webform project. -Add the xml file...
1
by: Nick | last post by:
I am working on a website for a client and one of their requirements was to have a mailing list. I decided to XSLT to transform "templates" to HTML so that editing was very easy and less time...
4
by: gouranga | last post by:
Sablotron keeps giving an error (non-XSL instruction) on the line with this code: <xsl:result-document href="slideshow/index.html" format="html"> Is this implemented in Sablotron? It's quite...
5
by: Gilgamesh | last post by:
Hi. I'm looking for an easy way to generate, automatically, an XSLT from an XSD, to be applied to a XML file (conforming the previous XSD) and generate an HTML. Many of you will tell me that...
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new...
0
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.