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 dls 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 dls 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 dls and copies them to the output.
It also evaluates the expressions that select the starting and ending h1s and also outputs the results.
Finally, for each pair of (starting h1, ending h1) it evaluates an XPath expression that selects all dls 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 dls):
<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>