XSLT current-groups() issue - xslt-2.0

I've been having a bit of trouble with an HTML file that I'm trying to translate. Basically, the relevant part of the source structure as it currently stands is this:
<h2 />
<h3 />
<table />
<table />
<h3 />
<table />
<table />
<h3 />
<table />
<h3 />
<h3 />
<table />
<table />
<h2 />
<h3 />
...
and so on. Each of the contents of these are being translated in different ways, but the problem I'm currently having is in grouping them correctly. Essentially, I want it to end up like the following:
<category>
<h2 />
<container>
<h3 />
<table />
<table />
</container>
<container>
<h3 />
<table />
<table />
</container>
<container>
<h3 />
<table />
</container>
<container>
<h3 />
</container>
<container>
<h3 />
<table />
<table />
</container>
</category>
<category>
<h2 />
<container>
<h3 />
...
to achieve this, I've been using the following code:
<xsl:for-each-group select="node()"group-starting-with="xh:h2">
<category>
<xsl:apply-templates select="xh:h2"/>
<xsl:for-each-group select="current-group()"
group-starting-with="xh:h3">
<container>
<xsl:apply-templates select="current-group()[node()]"/>
</container>
</xsl:for-each-group>
</category>
</xsl:for-each-group>
However, the output I get from this is as follows:
<category>
<h2 />
<container>
<h3 />
<table />
<table />
<h3 />
<table />
<table />
<h3 />
<table />
<h3 />
<h3 />
<table />
<table />
</container>
</category>
<category>
<h2 />
<container>
<h3 />
...
The first for-loop function is working as expected, however the second does not appear to be. If I use <xsl:copy-of> to output the first element in the <current-group> in the second for-loop, it shows the <h2> element, where that element should not even be in the group.
If anyone can point out where I'm going wrong, or offer a better solution, it would be greatly appreciated.

I think you want to change
<xsl:for-each-group select="node()" group-starting-with="xh:h2">
<category>
<xsl:apply-templates select="xh:h2"/>
<xsl:for-each-group select="current-group()"
group-starting-with="xh:h3">
to
<xsl:for-each-group select="*" group-starting-with="xh:h2">
<category>
<xsl:apply-templates select="."/>
<xsl:for-each-group select="current-group() except ."
group-starting-with="xh:h3">
That way the inner for-each-group processes the h3 and table elements but no the h2 element starting the outer group.
If you need more help then consider to post small but complete samples with namespaces present allowing us to reproduce the problem with the undesired output.

I think you've simplified the problem and in doing so have introduced some red herrings.
The xsl:apply-templates select="h2" surely does nothing, because none of the nodes selected in the outer grouping has an h2 child.
In every group selected by the outer for-each-group, except the first, the first node in the group will be an h2 element, by definition. Your inner for-each-group will partition the sequence of nodes starting with an h2 into: first, a group that starts with the h2 (because every node becomes part of some group), and then a sequence of groups each of which starts with an h3. You need to split out the first (non-h3) group and treat it differently, because you don't want to generate a container element in this case. So you need an xsl:choose in the inner for-each-group, typically with the condition xsl:when test="self::h2" to detect that you're processing the special first group.
Having said all that I can't see why you aren't getting a container element for each h3 element. I think this must be caused by something that you haven't shown us (perhaps a namespace issue?)

Related

Tiles 3 override a nested attribute

I'm have a problem with Tiles 3 with Struts2. I can't seem to override an attribute of a nested tiles-definition.
Here's the relevant parts of my web.xml:
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<listener>
<listener-class>org.apache.struts2.tiles.StrutsTilesListener</listener-class>
</listener>
Here's my struts.xml
<package name="helloworld" extends="tiles-default" namespace="/secure">
<result-types>
<result-type name="tiles" class="org.apache.struts2.views.tiles.TilesResult" default="true" />
</result-types>
<interceptors>
<interceptor name="s2sLogging" class="com.s2s.web.s2.S2Interceptor" />
<interceptor-stack name="s2sStack">
<interceptor-ref name="timer" />
<interceptor-ref name="defaultStack" />
<interceptor-ref name="s2sLogging" />
</interceptor-stack>
</interceptors>
<default-interceptor-ref name="s2sStack" />
<action name="howitworks" class="com.s2s.web.s2.S2RootAction" >
<result name="success" type="tiles">.howItWorks.landing</result>
</action>
Here's my tiles.xml
<definition name="s2s.rightNav" template="/WEB-INF/s2/pages/common/rightNav.jsp" >
</definition>
<definition name="s2s.pageContent" template="/WEB-INF/s2/pages/pageContent.jsp">
<put-attribute name="box" value="true" /> <!-- change to false to remove grey box behind text -->
<put-attribute name="rightNav" value="s2s.rightNav" />
</definition>
<!-- overall page layout -->
<definition name="page.layout" template="/WEB-INF/s2/pages/page.jsp">
<put-attribute name="pageTitlePrefix" value="s2s.com" type="string"/>
<put-attribute name="pageTitle" value=" " type="string"/>
<put-attribute name="headContent" value="s2s.headContent" />
<put-attribute name="extraHeadContent" value=".tile.empty" />
<put-attribute name="topNav" value="s2s.topNav" />
<put-attribute name="topNavSubNav" value="s2s.topNavSubNav" />
<put-attribute name="pageContent" value="s2s.pageContent" />
<put-attribute name="footer" value="s2s.footer" type="string"/>
<put-attribute name="SEOkeywords" value="s2s, ship to storage, moving storage services, self-storage, moving storage, self storage shipping, send to storage, ship to self storage, shipping storage, mail storage, self storage pick up and delivery" />
<put-attribute name="SEOdescription" value="The worlds most convenient self-storage. s2s combines shipping, elf storage, and service -- prices from $2.79 a box. Boxes are picked up from your doorstep and stored at our climate controlled, secure warehouse. s2s's flexible pricing grows as your needs grow. A valuable shipping and storage resource for moving, relocation, offices, students, trade shows, and more." />
<put-attribute name="pageSEOkeywords" value=" " type="string"/>
<put-attribute name="pageSEOdescription" value="s2s.com - " type="string"/>
<put-attribute name="debugPage" value="v.101" type="string"/>
</definition>
<!-- PAGE DEFNINITIONS -->
<definition name=".howItWorks.landing" extends="page.layout">
<put-attribute name="pageTitle" value="How Mail Storage Works " type="string"/>
<put-attribute name="selectedTab" value="howItWorks" type="string"/>
<put-attribute name="pageSEOkeywords" value="how it works, " type="string"/>
<put-attribute name="pageSEOdescription" value="How It Works | " type="string"/>
<put-attribute name="rightNavCTAs" value="estimateBoxSize,helpfulLinks" type="string" cascade="true"/>
<put-attribute name="mainBodyContent" value="s2s.howItWorks.MainBodyContent" cascade="true"/>
</definition>
<definition name="s2s.howItWorks.MainBodyContent" template="/WEB-INF/s2/pages/howItWorks.jsp" />
I want to override the mainBodyContent and the rightNavCTAs attributes of with the definition of .howItWorks.landing. However, when I print out the actual value in the jsp , rightNavCTAs is null (and I think it means that the value is not propagating down even though I use cascade="true").
According to the Apache Tiles 3 documentation here, I should be able to nest using subdefinitions like I have above, and then extend and override attributes. The cascade is supposed to propagate attributes.
Needless to say, I can't get it to work. Can anyone spot my flaw?
as Requested, here are my jsps. thanks for looking.
all jsps have this at the top:
<%# page contentType="text/html; charset=UTF-8" %>
<%# taglib prefix="s" uri="/struts-tags" %>
<%# taglib uri="http://tiles.apache.org/tags-tiles" prefix="tiles"%>
Here is My page.jsp (stripped of css):
<tiles:importAttribute scope="request"/>
<html>
<head>
<link rel="stylesheet" type="text/css" href="<%=request.getContextPath()%>/css/stylesheet.css" />
<link rel="stylesheet" type="text/css" href="<%=request.getContextPath()%>/css/jmesa.css">
<title>
<tiles:getAsString name="pageTitlePrefix" /> - <tiles:getAsString name="pageTitle" />
</title>
<tiles:insertAttribute name="headContent" />
<tiles:insertAttribute name="extraHeadContent" />
</head>
<body>
<div id="page">
<tiles:insertAttribute name="topNav" />
<tiles:insertAttribute name="topNavSubNav" />
<tiles:insertAttribute name="pageContent" />
<tiles:insertAttribute name="footer" />
</div>
</body>
</html>
Here is may pageContent.jsp (stripped of css):
<table >
<tr>
<td >
<!-- Box Table Starts here-->
<s:if test="%{#attr['box'] == 'true'}">
<table >
<tr>
<td /></td>
<td /></td>
<td /></td>
</tr>
<tr>
<td > </td>
<td >
<!-- Insert Main Body Content1 -->
<tiles:insertAttribute name="mainBodyContent" />
<!-- End of Main Body Content1 -->
</td>
<td > </td>
</tr>
<tr>
<td /></td>
<td > </td>
<td /></td>
</tr>
</table>
</s:if>
<s:else>
<!-- Insert Main Body Content -->
<tiles:insertAttribute name="mainBodyContent" />
<!-- End of Main Body Content -->
</s:else>
</td>
<td > </td>
<td >
<tiles:insertAttribute name="rightNav" />
</td>
</tr>
</table>
<!-- End Page Content -->
And here is my howitworks.jsp (again, stripped of css). This is supposed to override the mainBodyContent attribute, but I can't get it to work :
<table >
<tr>
<td />Test... how it works</td>
<td /></td>
<td /></td>
</tr>
</table>

ASP.NET does not seem to see the .css or .js for DataTables

I'm working on displaying tabular data from a SQL database in a 'aspx' page that I added into an mvc template project I have made inside Visual Studio 2013.
I have a SQL DataSource connected to a database bringing back a basic table. I can display the information in the 'DataTable.aspx' file. I am not able to get the dataTables.js or the .css files to run. Or I do not think that they are running. This is what I have checked so far..
I can see jquery as having loaded, and I did install both jquery and datatables in the 'NuGet' package manager through Visual Studio 2013 (demo)
The .net tab in FireFox (sometimes shows that the .js and .cs files in the debug session in black or gray.
-I think my 'DataTables.aspx' file is correct (below).
<%: Title %>.
TaskTable
<div>
<asp:SqlDataSource ID="SqlDataSource1" runat="server"
ConnectionString="<%$ ConnectionStrings:TaskRFIDatabaseConnectionString %>"
SelectCommand="SELECT [TaskID], [TaskTypeID], [TaskCreatedBy], [TaskName], [TaskDescription], [TaskCreatedDateTime] FROM [TaskTable]">
</asp:SqlDataSource>
<asp:Repeater ID="Repeater1" runat="server" DataSourceID="SqlDataSource1">
<HeaderTemplate>
<table id="DataTable">
<thead>
<tr>
<th>TaskID</th>
<th>TaskTypeID</th>
<th>TaskCreatedBy</th>
<th>TaskName</th>
<th>TaskDescription</th>
<th>TaskCreatedDateTime</th>
</tr>
</thead>
</HeaderTemplate>
<ItemTemplate>
<tr>
<td><%# Eval("TaskId") %></td>
<td><%# Eval("TaskTypeID") %></td>
<td><%# Eval("TaskCreatedBy") %></td>
<td><%# Eval("TaskName") %></td>
<td><%# Eval("TaskDescription") %></td>
<td><%# Eval("TaskCreatedDateTime") %></td>
</tr>
</ItemTemplate>
<FooterTemplate>
</table>
</FooterTemplate>
</asp:Repeater>
</div>
The site master has the references to the .js and .css files for dataTables.
<%# Master Language="C#" AutoEventWireup="true" CodeBehind="Site.master.cs" Inherits="Compass.SiteMaster" %>
<!DOCTYPE html>
<html lang="en">
<head runat="server">
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title><%: Page.Title %> - Compass</title>
<link href="Content/DataTables-1.10.3/css/jquery.dataTables.css" rel="stylesheet" />
<script src="Scripts/jquery-2.1.1.js"></script>
<script src="Scripts/DataTables-1.10.3/media/js/jquery.dataTables.js"></script>
<asp:PlaceHolder runat="server">
<%: Scripts.Render("~/bundles/modernizr") %>
</asp:PlaceHolder>
<webopt:bundlereference runat="server" path="~/Content/css" />
<link href="~/favicon.ico" rel="shortcut icon" type="image/x-icon" />
</head>
<body>
<form runat="server">
<asp:ScriptManager runat="server">
<Scripts>
<%--To learn more about bundling scripts in ScriptManager see http://go.microsoft.com/fwlink/?LinkID=301884 --%>
<%--Framework Scripts--%>
<asp:ScriptReference Name="MsAjaxBundle" />
<asp:ScriptReference Name="jquery" />
<asp:ScriptReference Name="bootstrap" />
<asp:ScriptReference Name="respond" />
<asp:ScriptReference Name="WebForms.js" Assembly="System.Web" Path="~/Scripts/WebForms/WebForms.js" />
<asp:ScriptReference Name="WebUIValidation.js" Assembly="System.Web" Path="~/Scripts/WebForms/WebUIValidation.js" />
<asp:ScriptReference Name="MenuStandards.js" Assembly="System.Web" Path="~/Scripts/WebForms/MenuStandards.js" />
<asp:ScriptReference Name="GridView.js" Assembly="System.Web" Path="~/Scripts/WebForms/GridView.js" />
<asp:ScriptReference Name="DetailsView.js" Assembly="System.Web" Path="~/Scripts/WebForms/DetailsView.js" />
<asp:ScriptReference Name="TreeView.js" Assembly="System.Web" Path="~/Scripts/WebForms/TreeView.js" />
<asp:ScriptReference Name="WebParts.js" Assembly="System.Web" Path="~/Scripts/WebForms/WebParts.js" />
<asp:ScriptReference Name="Focus.js" Assembly="System.Web" Path="~/Scripts/WebForms/Focus.js" />
<asp:ScriptReference Name="WebFormsBundle" />
<%--Site Scripts--%>
</Scripts>
</asp:ScriptManager>
<div class="navbar navbar-inverse navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" runat="server" href="~/">Application name</a>
</div>
<div class="navbar-collapse collapse">
<ul class="nav navbar-nav">
<li><a runat="server" href="~/">Home</a></li>
<li><a runat="server" href="~/About">About</a></li>
<li><a runat="server" href="~/Contact">Contact</a></li>
<li><a runat="server" href="~/DataTable">DataTable</a></li>
</ul>
<asp:LoginView runat="server" ViewStateMode="Disabled">
<AnonymousTemplate>
<ul class="nav navbar-nav navbar-right">
<li><a runat="server" href="~/Account/Register">Register</a></li>
<li><a runat="server" href="~/Account/Login">Log in</a></li>
</ul>
</AnonymousTemplate>
<LoggedInTemplate>
<ul class="nav navbar-nav navbar-right">
<li><a runat="server" href="~/Account/Manage" title="Manage your account">Hello, <%: Context.User.Identity.GetUserName() %> !</a></li>
<li>
<asp:LoginStatus runat="server" LogoutAction="Redirect" LogoutText="Log off" LogoutPageUrl="~/" OnLoggingOut="Unnamed_LoggingOut" />
</li>
</ul>
</LoggedInTemplate>
</asp:LoginView>
</div>
</div>
</div>
<div class="container body-content">
<asp:ContentPlaceHolder ID="HeaderContent" runat="server">
<link href="Content/DataTables-1.10.3/css/jquery.dataTables.css" rel="stylesheet" />
<script src="Scripts/jquery-2.1.1.js"></script>
<script src="Scripts/DataTables-1.10.3/jquery.dataTables.js"></script>
</asp:ContentPlaceHolder>
<asp:ContentPlaceHolder ID="MainContent" runat="server">
</asp:ContentPlaceHolder>
<hr />
<footer>
<p>© <%: DateTime.Now.Year %> - My ASP.NET Application</p>
</footer>
</div>
</form>
</body>
</html>
Where else would you check? All of the examples I have read have been either dealing with a simple page or are using different methods. This is from a base web/mvc template from Visual Studio 2013 and jQuery dataTables.js installed through NuGet.
Some of the other pages I have already hit:
jQuery DataTable not working in asp.net mvc 4
http://www.codeproject.com/Articles/155422/jQuery-DataTables-and-ASP-NET-MVC-Integration-Part
Is there anyplace else I should be looking?
Andy..
Woo Hoo.. Found it.
I'm learning the ropes in the world of MVC 5 and jQuery/dataTables.
Let me restate the problem: I had a VS(2013) project (Web / .NetFramework4.5.1 / ASP.NET Web Application / WebForms (checkd 'WebForms', MVC)) I added in the references for jQuery & DataTables through the NuGet Package Manager. wrongly thought that this magically put all of the references I needed for the wireup
I added the following objects via drag drop to the cookie cutter template I used above from Data toolbox:
Repeater (source set to the 'SqlDataSource1')
SqlDataSource (setup with connection to my database)
So I thought I had all of the jQuery / js / css for using DataTables. I have done this in straight javascript before (Aptana) and could not figure out where the references for the css would have to be inserted. I about drove me crazy.
I know, get to it.. The scripts were there but not really doing anything. A table was generated but didn't have the css or scripty goodness that I wanted. That was the problem no css or script behavior I expected from dataTables.
What I did:
1. Started over with a new project, Added jQuery and DataTables through NuGet Package Manager.
2. Opened up "Site.Master" file and added references to the css in the section
<Link href="Content/DataTables-1.10.3/css/jquery.dataTables.css" rel="stylesheet"/>
Added the reference to the jquery.dataTables.js file in the same file "Site.Master"..
<asp:ScriptManager runat="server">
<Scripts>
<%--Framework Scripts--%>
<asp:ScriptReference Name="MsAjaxBundle" />
<asp:ScriptReference Name="jquery" />
<asp:ScriptReference Path="~/Scripts/DataTables-1.10.3/jquery.dataTables.js" />
<asp:ScriptReference Name="bootstrap" />
<asp:ScriptReference Name="respond" />
<asp:ScriptReference Name="WebForms.js" Assembly="System.Web" Path="~/Scripts/WebForms/WebForms.js" />
<asp:ScriptReference Name="WebUIValidation.js" Assembly="System.Web" Path="~/Scripts/WebForms/WebUIValidation.js" />
<asp:ScriptReference Name="MenuStandards.js" Assembly="System.Web" Path="~/Scripts/WebForms/MenuStandards.js" />
<asp:ScriptReference Name="GridView.js" Assembly="System.Web" Path="~/Scripts/WebForms/GridView.js" />
<asp:ScriptReference Name="DetailsView.js" Assembly="System.Web" Path="~/Scripts/WebForms/DetailsView.js" />
<asp:ScriptReference Name="TreeView.js" Assembly="System.Web" Path="~/Scripts/WebForms/TreeView.js" />
<asp:ScriptReference Name="WebParts.js" Assembly="System.Web" Path="~/Scripts/WebForms/WebParts.js" />
<asp:ScriptReference Name="Focus.js" Assembly="System.Web" Path="~/Scripts/WebForms/Focus.js" />
<asp:ScriptReference Name="WebFormsBundle" />
<%--Site Scripts--%>
</Scripts>
</asp:ScriptManager>
Cleaned / Rebuilt project
Added the final script call to the aspx page (final markup below)
<%# Page Title="Home Page" Language="C#" MasterPageFile="~/Site.Master" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="maybe._Default" %>
StaffID
LName
FName
WorkPhone
<%# Eval("StaffID") %>
<%# Eval("LName") %>
<%# Eval("FName") %>
<%# Eval("WorkPhone") %>
"myselection text">
$('#DataTable').dataTable();
Rebuilt and then ran it .. Worked!!.
Andy
sources:
http://www.youtube.com/watch?v=bfCLyaWHvcM Sql Repeater
http://msdn.microsoft.com/en-us/library/bb398991%28v=vs.100%29.aspx

how to implemant image map in flexslider?

I am using flexslider.
It is very easy to implement and customizing.
Now my every slide is a link.
is there any way to put to links for a single slide?
that needs to redirect to PAGE1 when click the left side of the image and must redirect to PAGE2 when click the right side.
Thanks in advance dear seniors...
I've found the answer.
The following method is working
<div class="flexslider">
<ul class="slides">
<!-- slide1 -->
<li>
<img src="images/slider/2.jpg" alt="" usemap="#map2" />
<map name="map2">
<area shape="rect" coords="494,2,961,745" href="http://www.john-anthony.com/mens/jeans/" alt=""/>
<area shape="rect" coords="0,4,482,749" href="http://www.john-anthony.com/vivienne-westwood/blazer-jackets/burgundy/jacket-waistcoat-check/vw024-a13-bur/" alt=""/>
</map>
</li>
</ul>
</div>
I've found the answer. The following method is working
<div class="flexslider">
<ul class="slides">
<!-- slide1 -->
<li>
<img src="images/slider/2.jpg" alt="" usemap="#map2" />
<map name="map2">
<area shape="rect" coords="494,2,961,745" href="http://www.john-anthony.com/mens/jeans/" alt=""/>
<area shape="rect" coords="0,4,482,749" href="http://www.john-anthony.com/vivienne-westwood/blazer-jackets/burgundy/jacket-waistcoat-check/vw024-a13-bur/" alt=""/>
</map>
</li>
</ul>
</div>

Displaytag in struts2 checked columns dissappear when changing pages

i have this problem with displaytag...when i check some rows in the table and after go in another page for checking others the checked elements of the previous page disappear.
If i return to the previous page all the rows are unchecked...this is my code:
<%#taglib prefix="s" uri="/struts-tags" %>
<%#taglib prefix="display" uri="http://displaytag.sf.net" %>
…
<s:form action="actionSample" theme="simple">
<display:table
id="row"
name="tableSample"
requestURI="/sample"
sort="list"
pagesize="10"
cellpadding="0"
cellspacing="0"
>
<display:column property="one" title="ONE" sortable="true" />
<display:column property="two" title="TWO" sortable="true" />
<display:column headerClass="sortheader" title="SELECTION" style="text-align:center;">
<s:checkbox theme="simple" name="check" fieldValue='%{#attr.row.idOne}' />
</display:column>
</display:table>
<div>
<br>
</div>
<div align="right">
<s:submit type="button" label="SUBMIT"/>
</div>
How can i resolve this problem?, thank you for the answer...
P.S. i omitted the code of the action class, there is an array of string named "check" that stores the ids of the element selected

Grouping in XSLT 2.0 similar to br to p problems

In XSLT 1.0, a common question in forums was how to convert flat HTML into hierarchical XML, which many times boiled down to nesting text in between <br /> tags in <p> tags.
I have a similar problem, which I think I've partially solved using XSLT 2.0, but it's a new approach to me and I'd like to get a second opinion.
The XHTML source has <span class="pageStart"></span> scattered throughout. They can appear in several different parent nodes. I want to wrap all the nodes between one page start marker and the next in an <page> node. The solution I currently have is:
<xsl:template match="*[child::span[#class='pageStart']]">
<xsl:copy>
<xsl:copy-of select="#*" />
<xsl:for-each-group select="node()"
group-starting-with="span[#class='pageStart']">
<page>
<xsl:apply-templates select="current-group()"/>
</page>
</xsl:for-each-group>
</xsl:copy>
</xsl:template>
There's at least one flaw with this -- the parent node of the marker gets a <page> as a child node when I don't want it. In other works, if there's a <div> that has a child page marker anywhere in it, an <page> node is created as an immediate child of <div> in addition to the locations I expect.
I had hoped that I could simply make the template rule be <xsl:template match="span[#class='pageStart']"> but current-group() seems to be empty no matter what I try. The common sense approach I tried was <xsl:for-each-group select="node()" group-starting-with="span[#class='pageStart']">.
Is there an easier way to solve this problem that I'm missing?
EDIT
Here's an example of the input:
<?xml version="1.0" encoding="UTF-8"?>
<html>
<head></head>
<body>
<span class="pageStart"/>
<p>...</p>
<div>...</div>
<img />
<p></p>
<span class="pageStart"/>
<div>...</div>
<span class="pageStart"/>
<p>...</p>
<div>
<span class="pageStart"/>
<p>...</p>
<p>...</p>
<span class="pageStart"/>
<div>...</div>
<img/>
</div>
</body>
</html>
I assume the last two nested pages make this problem more difficult, so I'd be perfectly happy getting this as the output, or something close:
<?xml version="1.0" encoding="UTF-8"?>
<html>
<head></head>
<body>
<page>
<span class="pageStart"/>
<p>...</p>
<div>...</div>
<img />
<p></p>
</page>
<page>
<span class="pageStart"/>
<div>...</div>
</page>
<page>
<span class="pageStart"/>
<p>...</p>
<div>
<page>
<span class="pageStart"/>
<p>...</p>
<p>...</p>
</page>
<page>
<span class="pageStart"/>
<div>...</div>
<img/>
</page>
</div>
</page>
</body>
</html>
This transformation:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*[span/#class='pageStart']">
<xsl:copy>
<xsl:copy-of select="#*"/>
<xsl:for-each-group select="node()"
group-starting-with="span[#class='pageStart']">
<page>
<xsl:apply-templates select="current-group()"/>
</page>
</xsl:for-each-group>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
when applied on the provided XML document:
<html>
<head></head>
<body>
<span class="pageStart"/>
<p>...</p>
<div>...</div>
<img />
<p></p>
<span class="pageStart"/>
<div>...</div>
<span class="pageStart"/>
<p>...</p>
<div>
<span class="pageStart"/>
<p>...</p>
<p>...</p>
<span class="pageStart"/>
<div>...</div>
<img/>
</div>
</body>
</html>
produces the wanted, correct result:
<html>
<head/>
<body>
<page>
<span class="pageStart"/>
<p>...</p>
<div>...</div>
<img/>
<p/>
</page>
<page>
<span class="pageStart"/>
<div>...</div>
</page>
<page>
<span class="pageStart"/>
<p>...</p>
<div>
<page>
<span class="pageStart"/>
<p>...</p>
<p>...</p>
</page>
<page>
<span class="pageStart"/>
<div>...</div>
<img/>
</page>
</div>
</page>
</body>
</html>

Resources