Because the sequence of adjacent dl
elements must be immediately preceded and followed by h1
siblings, one expression that selects all such sequences of dl
elements is:
/*/dl[preceding-sibling::*[not(self::dl)][1][self::h1]
and
following-sibling::*[not(self::dl)][1][self::h1]
]
You can find all h1
elements each of which immediately precedes such wanted adjacent sequence of dl
s with this expression:
/*/h1[following-sibling::*[1][self::dl]
and
following-sibling::*[not(self::dl)][1][self::h1]
]
You can find all h1
elements each of which immediately follows such wanted adjacent sequence of dl
s with this expression:
/*/h1[preceding-sibling::*[1][self::dl]
and
preceding-sibling::*[not(self::dl)][1][self::h1]
]
Finally, here is an XSLT-based verification
This transformation just evaluates the expressions for finding all wanted sequences of dl
s and copies them to the output.
It also evaluates the expressions that select the starting and ending h1
s and also outputs the results.
Finally, for each pair of (starting h1
, ending h1
) it evaluates an XPath expression that selects all dl
s in this particular group and outputs the results.
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="/">
<xsl:copy-of select="
/*/dl[preceding-sibling::*[not(self::dl)][1][self::h1]
and
following-sibling::*[not(self::dl)][1][self::h1]
]"/>
========================
<xsl:variable name="vStartingH1s" select=
"/*/h1[following-sibling::*[1][self::dl]
and
following-sibling::*[not(self::dl)][1][self::h1]
]"/>
<xsl:copy-of select="$vStartingH1s"/>
========================
<xsl:variable name="vEndingH1s" select=
"/*/h1[preceding-sibling::*[1][self::dl]
and
preceding-sibling::*[not(self::dl)][1][self::h1]
]"/>
<xsl:copy-of select="$vEndingH1s"/>
========================
<xsl:for-each select="$vStartingH1s">
<xsl:variable name="vPos" select="position()"/>
<xsl:value-of select=
"concat(
'========== Group ', $vPos, ' ==========
')"/>
<xsl:copy-of select=
"following-sibling::*
[count(.| $vEndingH1s[position()=$vPos]/preceding-sibling::*)
=
count($vEndingH1s[position()=$vPos]/preceding-sibling::*)
]"/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
When this transformation is applied on the following XML document (the provided one, expanded to contain two groups of wanted dl
s):
<root>
<!-- all other kinds of xml elements including possibly other h1 -->
<a/>
<h1/>
<dl> some text
<dt>
other text
</dt>
</dl>
<!-- all other kinds of xml elements including possibly other h1 -->
<b/>
<h1/>
<h1>
<a>starting here</a>
</h1>
<dl>foo
<dt>
bar
</dt>
</dl>
<dl>foo
<dt>
bar
</dt>
</dl>
<!-- Many elements but all of them are dl -->
<dl>foo
<dt>
bar
</dt>
</dl>
<dl>foo
<dt>
bar
</dt>
</dl>
<h1>
<a>Ending here</a>
</h1>
<h1/>
<c/>
<h1/>
<!-- all other kinds of xml elements including possibly other h1 -->
<p/>
<dl>foo
<dt>
bar
</dt>
</dl>
<!-- all other kinds of xml elements including possibly other h1 -->
<h1/>
<d/>
<h1>
<a>starting here</a>
</h1>
<dl>foo
<dt>
bar
</dt>
</dl>
<dl>foo
<dt>
bar
</dt>
</dl>
<h1>
<a>Ending here</a>
</h1>
<e/>
<h1/>
<f/>
the wanted, correct results are produced:
<dl>foo
<dt>
bar
</dt>
</dl>
<dl>foo
<dt>
bar
</dt>
</dl>
<dl>foo
<dt>
bar
</dt>
</dl>
<dl>foo
<dt>
bar
</dt>
</dl>
<dl>foo
<dt>
bar
</dt>
</dl>
<dl>foo
<dt>
bar
</dt>
</dl>
========================
<h1>
<a>starting here</a>
</h1>
<h1>
<a>starting here</a>
</h1>
========================
<h1>
<a>Ending here</a>
</h1>
<h1>
<a>Ending here</a>
</h1>
========================
========== Group 1 ==========
<dl>foo
<dt>
bar
</dt>
</dl>
<dl>foo
<dt>
bar
</dt>
</dl>
<dl>foo
<dt>
bar
</dt>
</dl>
<dl>foo
<dt>
bar
</dt>
</dl>========== Group 2 ==========
<dl>foo
<dt>
bar
</dt>
</dl>
<dl>foo
<dt>
bar
</dt>
</dl>