XPath / XSLT: как вкладывать элементы одного уровня в новый элемент до определенного элемента?

У меня есть следующий фрагмент HTML:

<p>
    This is
    <font>start</font>
    just some <i>happy</i> text
    <font>stop</font>
    that might continue here.
</p>

и я хочу использовать XSLT, чтобы превратить его в это:

<p>
    This is
    <hi>
       just some <i>happy</i> text
    </hi>
    that might continue here.
</p>

так что все (узлы, текст и комментарии) между font[text() = "start"] и font[text() = "stop"] вложено в новый элемент hi.

Я попытался:

<!-- identity template here-->

<xsl:template match="font[text()='start']">
    <xsl:element name="hi">
       <!-- FOLLOWING:SIBLING UNTIL THE NEXT font[text()='stop'] -->
       <xsl:value-of select="following-sibling[????]"/>
    </xsl:element>
</xsl:template>

<xsl:template match="font[text()='stop']"><!-- do nothing--></xsl:template>

но ???? где я не мог найти правильное правило. Я поигрался с полчаса, потом подумал, что спрашивать может быть быстрее.

Важно, чтобы это было именно до следующей остановки, так как таких конструкций в одном p-элементе может быть множество.

Спасибо


person J. Schäuble    schedule 19.11.2019    source источник
comment
Это во многом зависит от того, используете ли вы XSLT 1.0 или 2.0. В 2.0 вы можете использовать xsl:for-each-group, в 1.0 вам придется использовать родственную рекурсию, что довольно сложно. Это также зависит от того, можете ли вы иметь несколько пар начала/конца в абзаце, и от того, что вы хотите сделать, если они неправильно соединены. Пожалуйста, в вопросах XSLT всегда говорите, какая версия вам требуется.   -  person Michael Kay    schedule 19.11.2019
comment
Спасибо, это XSLT 2.0, и в одном p может быть несколько пар, но флаги начала-остановки могут (насколько я оценил набор данных) не быть вложенными в другой диапазон начала-остановки. Для каждой группы может быть то, что я ищу, но я еще не мог понять, как это сделать.   -  person J. Schäuble    schedule 20.11.2019


Ответы (1)


Что-то вроде этого, возможно:

<xsl:for-each-group select="node()" group-starting-with="font[.='start']">
  <xsl:for-each-group select="current-group()" group-ending-with="font[.='end']">
    <xsl:choose>
    <xsl:when test="current-group()[self::font[.='start'] and self::font[.='end']">
      <hi>
        <xsl:copy-of select="current-group()[not(self::font)]"/>
      </hi>
    </xsl:when>
    <xsl:otherwise>
      <xsl:copy-of select="current-group()"/>
    </
  </
</

Не испытано.

person Michael Kay    schedule 20.11.2019